diff options
Diffstat (limited to 'services')
25 files changed, 1485 insertions, 635 deletions
diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 98daaf5..a8bb636 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -1285,6 +1285,9 @@ protected: if (haveSizeBias) { *outSize += sizeBias; } + if (*outSize < 0) { + *outSize = 0; + } } } mCalibration; diff --git a/services/java/Android.mk b/services/java/Android.mk index 95b28d9..8c3d0f0 100644 --- a/services/java/Android.mk +++ b/services/java/Android.mk @@ -11,7 +11,7 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE:= services -LOCAL_JAVA_LIBRARIES := android.policy telephony-common +LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common include $(BUILD_JAVA_LIBRARY) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index bb0d248..a0e6dd1 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3916,13 +3916,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { Random rand = new Random(); mParams = params; - try { - if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; - return result; - } + if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { + log("isMobileOk: not mobile capable"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + return result; + } + try { // Enable fail fast as we'll do retries here and use a // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 43f95c3..7e83396 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -16,11 +16,14 @@ package com.android.server; +import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; + import com.android.internal.os.storage.ExternalStorageFormatter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; +import com.android.org.conscrypt.TrustedCertificateStore; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -49,6 +52,7 @@ import android.content.pm.Signature; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.net.Uri; +import android.os.AsyncTask; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -66,7 +70,12 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.Credentials; +import android.security.IKeyChainService; +import android.security.KeyChain; +import android.security.KeyChain.KeyChainConnection; import android.util.AtomicFile; +import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; @@ -75,6 +84,7 @@ import android.util.Xml; import android.view.IWindowManager; import android.view.WindowManagerPolicy; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -82,8 +92,14 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.security.KeyStore.TrustedCertificateEntry; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.text.DateFormat; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -1870,6 +1886,76 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return !"".equals(state); } + public boolean installCaCert(byte[] certBuffer) throws RemoteException { + mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null); + KeyChainConnection keyChainConnection = null; + byte[] pemCert; + try { + X509Certificate cert = parseCert(certBuffer); + pemCert = Credentials.convertToPem(cert); + } catch (CertificateException ce) { + Log.e(TAG, "Problem converting cert", ce); + return false; + } catch (IOException ioe) { + Log.e(TAG, "Problem reading cert", ioe); + return false; + } + try { + keyChainConnection = KeyChain.bind(mContext); + try { + keyChainConnection.getService().installCaCertificate(pemCert); + return true; + } finally { + if (keyChainConnection != null) { + keyChainConnection.close(); + keyChainConnection = null; + } + } + } catch (InterruptedException e1) { + Log.w(TAG, "installCaCertsToKeyChain(): ", e1); + Thread.currentThread().interrupt(); + } + return false; + } + + private static X509Certificate parseCert(byte[] certBuffer) + throws CertificateException, IOException { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream( + certBuffer)); + } + + public void uninstallCaCert(final byte[] certBuffer) { + mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null); + TrustedCertificateStore certStore = new TrustedCertificateStore(); + String alias = null; + try { + X509Certificate cert = parseCert(certBuffer); + alias = certStore.getCertificateAlias(cert); + } catch (CertificateException ce) { + Log.e(TAG, "Problem creating X509Certificate", ce); + return; + } catch (IOException ioe) { + Log.e(TAG, "Problem reading certificate", ioe); + return; + } + try { + KeyChainConnection keyChainConnection = KeyChain.bind(mContext); + IKeyChainService service = keyChainConnection.getService(); + try { + service.deleteCaCertificate(alias); + } catch (RemoteException e) { + Log.e(TAG, "from CaCertUninstaller: ", e); + } finally { + keyChainConnection.close(); + keyChainConnection = null; + } + } catch (InterruptedException ie) { + Log.w(TAG, "CaCertUninstaller: ", ie); + Thread.currentThread().interrupt(); + } + } + void wipeDataLocked(int flags) { // If the SD card is encrypted and non-removable, we have to force a wipe. boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted(); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index a32699a..9761441 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -420,19 +420,7 @@ public class LocationManagerService extends ILocationManager.Stub { Slog.e(TAG, "no geocoder provider found"); } - // bind to geofence provider - GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, - com.android.internal.R.bool.config_enableGeofenceOverlay, - com.android.internal.R.string.config_geofenceProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames, - mLocationHandler, - gpsProvider.getGpsGeofenceProxy()); - if (provider == null) { - 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, @@ -441,10 +429,21 @@ public class LocationManagerService extends ILocationManager.Stub { com.android.internal.R.bool.config_enableFusedLocationOverlay, com.android.internal.R.string.config_fusedLocationProviderPackageName, com.android.internal.R.array.config_locationProviderPackageNames); - if(fusedProxy == null) { Slog.e(TAG, "No FusedProvider found."); } + + // bind to geofence provider + GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, + com.android.internal.R.bool.config_enableGeofenceOverlay, + com.android.internal.R.string.config_geofenceProviderPackageName, + com.android.internal.R.array.config_locationProviderPackageNames, + mLocationHandler, + gpsProvider.getGpsGeofenceProxy(), + flpHardwareProvider.getGeofenceHardware()); + if (provider == null) { + Slog.e(TAG, "no geofence provider found"); + } } /** @@ -549,30 +548,52 @@ public class LocationManagerService extends ILocationManager.Stub { return s.toString(); } + /** + * Update AppOp monitoring for this receiver. + * + * @param allow If true receiver is currently active, if false it's been removed. + */ public void updateMonitoring(boolean allow) { if (mHideFromAppOps) { return; } + boolean requestingLocation = false; + boolean requestingHighPowerLocation = false; + if (allow) { + // See if receiver has any enabled update records. Also note if any update records + // are high power (has a high power provider with an interval under a threshold). + for (UpdateRecord updateRecord : mUpdateRecords.values()) { + if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) { + requestingLocation = true; + LocationProviderInterface locationProvider + = mProvidersByName.get(updateRecord.mProvider); + ProviderProperties properties = locationProvider != null + ? locationProvider.getProperties() : null; + if (properties != null + && properties.mPowerRequirement == Criteria.POWER_HIGH + && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) { + requestingHighPowerLocation = true; + break; + } + } + } + } + // First update monitoring of any location request (including high power). - mOpMonitoring = updateMonitoring(allow, mOpMonitoring, + mOpMonitoring = updateMonitoring( + requestingLocation, + mOpMonitoring, AppOpsManager.OP_MONITOR_LOCATION); // Now update monitoring of high power requests only. - // A high power request is any gps request with interval under a threshold. - boolean allowHighPower = allow; - if (allowHighPower) { - UpdateRecord gpsRecord = mUpdateRecords.get(LocationManager.GPS_PROVIDER); - if (gpsRecord == null - || gpsRecord.mRequest.getInterval() > HIGH_POWER_INTERVAL_MS) { - allowHighPower = false; - } - } boolean wasHighPowerMonitoring = mOpHighPowerMonitoring; - mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring, + mOpHighPowerMonitoring = updateMonitoring( + requestingHighPowerLocation, + mOpHighPowerMonitoring, AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION); if (mOpHighPowerMonitoring != wasHighPowerMonitoring) { - // send an intent to notify that a high power request has been added/removed. + // 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); } @@ -689,6 +710,10 @@ public class LocationManagerService extends ILocationManager.Stub { } public boolean callProviderEnabledLocked(String provider, boolean enabled) { + // First update AppOp monitoring. + // An app may get/lose location access as providers are enabled/disabled. + updateMonitoring(true); + if (mListener != null) { try { synchronized (this) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index a6d7e3c..8f4b6c2 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -21,12 +21,12 @@ import static com.android.internal.util.XmlUtils.readIntAttribute; import static com.android.internal.util.XmlUtils.writeIntAttribute; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; - import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import android.app.AppOpsManager; import android.appwidget.AppWidgetManager; import android.util.ArrayMap; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; @@ -52,6 +52,7 @@ import com.android.server.pm.UserManagerService; import com.android.server.wm.AppTransition; import com.android.server.wm.StackBox; import com.android.server.wm.WindowManagerService; + import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -154,6 +155,7 @@ import android.os.UpdateLock; import android.os.UserHandle; import android.provider.Settings; import android.text.format.Time; +import android.util.ArraySet; import android.util.AtomicFile; import android.util.EventLog; import android.util.Log; @@ -536,7 +538,7 @@ public final class ActivityManagerService extends ActivityManagerNative * This is the process holding what we currently consider to be * the "home" activity. */ - ProcessRecord mHomeProcess; + ArraySet<ProcessRecord> mHomeProcess = new ArraySet<ProcessRecord>(); /** * This is the process holding the activity the user last visited that @@ -8062,12 +8064,10 @@ public final class ActivityManagerService extends ActivityManagerNative if (activity == null) { Slog.w(TAG, "getAssistContextExtras error: no resumed activity"); validActivity = false; - } - if (activity.app == null || activity.app.thread == null) { + } else if (activity.app == null || activity.app.thread == null) { Slog.w(TAG, "getAssistContextExtras error: no process for " + activity); validActivity = false; - } - if (activity.app.pid == Binder.getCallingPid()) { + } else if (activity.app.pid == Binder.getCallingPid()) { Slog.w(TAG, "getAssistContextExtras error: request process same as " + activity); validActivity = false; } @@ -8154,18 +8154,20 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void convertFromTranslucent(IBinder token) { + public boolean convertFromTranslucent(IBinder token) { final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { final ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r == null) { - return; + return false; } if (r.changeWindowTranslucency(true)) { mWindowManager.setAppFullscreen(token, true); mStackSupervisor.ensureActivitiesVisibleLocked(null, 0); + return true; } + return false; } } finally { Binder.restoreCallingIdentity(origId); @@ -8173,19 +8175,21 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void convertToTranslucent(IBinder token) { + public boolean convertToTranslucent(IBinder token) { final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { final ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r == null) { - return; + return false; } if (r.changeWindowTranslucency(false)) { r.task.stack.convertToTranslucent(r); mWindowManager.setAppFullscreen(token, false); mStackSupervisor.ensureActivitiesVisibleLocked(null, 0); + return true; } + return false; } } finally { Binder.restoreCallingIdentity(origId); @@ -8953,11 +8957,11 @@ public final class ActivityManagerService extends ActivityManagerNative // replaced by a third-party app, clear the package preferred activities from packages // with a home activity running in the process to prevent a repeatedly crashing app // from blocking the user to manually clear the list. - if (app == mHomeProcess && mHomeProcess.activities.size() > 0 - && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - Iterator<ActivityRecord> it = mHomeProcess.activities.iterator(); - while (it.hasNext()) { - ActivityRecord r = it.next(); + final ArrayList<ActivityRecord> activities = app.activities; + if (mHomeProcess.contains(app) && activities.size() > 0 + && (app.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); if (r.isHomeActivity()) { Log.i(TAG, "Clearing package preferred activities from " + r.packageName); try { @@ -10232,13 +10236,20 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(" mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray)); } } - if (mHomeProcess != null && (dumpPackage == null - || mHomeProcess.pkgList.containsKey(dumpPackage))) { - if (needSep) { - pw.println(); - needSep = false; + if (!mHomeProcess.isEmpty()) { + final int size = mHomeProcess.size(); + ProcessRecord[] processes = new ProcessRecord[size]; + mHomeProcess.toArray(processes); + for (int processNdx = 0; processNdx < size; ++processNdx) { + final ProcessRecord app = processes[processNdx]; + if (dumpPackage == null || app.pkgList.containsKey(dumpPackage)) { + if (needSep) { + pw.println(); + needSep = false; + } + pw.println(" mHomeProcess[" + processNdx + "]: " + app); + } } - pw.println(" mHomeProcess: " + mHomeProcess); } if (mPreviousProcess != null && (dumpPackage == null || mPreviousProcess.pkgList.containsKey(dumpPackage))) { @@ -11739,10 +11750,10 @@ public final class ActivityManagerService extends ActivityManagerNative } return inLaunching; } - + /** * Main code for cleaning up a process when it has gone away. This is - * called both as a result of the process dying, or directly when stopping + * called both as a result of the process dying, or directly when stopping * a process when running in single process mode. */ private final void cleanUpApplicationRecordLocked(ProcessRecord app, @@ -11753,7 +11764,7 @@ public final class ActivityManagerService extends ActivityManagerNative mProcessesToGc.remove(app); mPendingPssProcesses.remove(app); - + // Dismiss any open dialogs. if (app.crashDialog != null && !app.forceCrashReport) { app.crashDialog.dismiss(); @@ -11770,7 +11781,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.crashing = false; app.notResponding = false; - + app.resetPackageList(mProcessStats); app.unlinkDeathRecipient(); app.thread = null; @@ -11803,7 +11814,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (checkAppInLaunchingProvidersLocked(app, false)) { restart = true; } - + // Unregister from connected content providers. if (!app.conProviders.isEmpty()) { for (int i=0; i<app.conProviders.size(); i++) { @@ -11830,7 +11841,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } } - + skipCurrentReceiverLocked(app); // Unregister any receivers. @@ -11861,6 +11872,8 @@ public final class ActivityManagerService extends ActivityManagerNative } mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget(); + mHomeProcess.remove(app); + // If the caller is restarting this app, then leave it in its // current lists and let the caller take care of it. if (restarting) { @@ -11890,8 +11903,8 @@ public final class ActivityManagerService extends ActivityManagerNative "Clean-up removing on hold: " + app); mProcessesOnHold.remove(app); - if (app == mHomeProcess) { - mHomeProcess = null; + if (mHomeProcess.contains(app)) { + mHomeProcess.remove(app); } if (app == mPreviousProcess) { mPreviousProcess = null; @@ -13817,7 +13830,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (app == mHomeProcess) { + if (mHomeProcess.contains(app)) { if (adj > ProcessList.HOME_APP_ADJ) { // This process is hosting what we currently consider to be the // home app, so we don't want to let it go into the background. @@ -13884,7 +13897,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (procState > ActivityManager.PROCESS_STATE_SERVICE) { procState = ActivityManager.PROCESS_STATE_SERVICE; } - if (app.hasShownUi && app != mHomeProcess) { + if (app.hasShownUi && !mHomeProcess.contains(app)) { // If this process has shown some UI, let it immediately // go to the LRU list because it may be pretty heavy with // UI stuff. We'll tag it with a label just to help @@ -13947,7 +13960,7 @@ public final class ActivityManagerService extends ActivityManagerNative if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { // Not doing bind OOM management, so treat // this guy more like a started service. - if (app.hasShownUi && app != mHomeProcess) { + if (app.hasShownUi && !mHomeProcess.contains(app)) { // If this process has shown some UI, let it immediately // go to the LRU list because it may be pretty heavy with // UI stuff. We'll tag it with a label just to help @@ -14002,7 +14015,7 @@ public final class ActivityManagerService extends ActivityManagerNative // about letting this process get into the LRU // list to be killed and restarted if needed for // memory. - if (app.hasShownUi && app != mHomeProcess + if (app.hasShownUi && !mHomeProcess.contains(app) && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { adjType = "cch-bound-ui-services"; } else { @@ -14116,7 +14129,7 @@ public final class ActivityManagerService extends ActivityManagerNative clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; } if (adj > clientAdj) { - if (app.hasShownUi && app != mHomeProcess + if (app.hasShownUi && !mHomeProcess.contains(app) && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { app.adjType = "cch-ui-provider"; } else { @@ -14976,7 +14989,7 @@ public final class ActivityManagerService extends ActivityManagerNative // to be good enough at this point that destroying // activities causes more harm than good. if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE - && app != mHomeProcess && app != mPreviousProcess) { + && !mHomeProcess.contains(app) && app != mPreviousProcess) { // Need to do this on its own message because the stack may not // be in a consistent state at this point. // For these apps we will also finish their activities diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index a0bbfad..2fefadf 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -2246,7 +2246,7 @@ final class ActivityStack { if (r.state == ActivityState.RESUMED || r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) { - if (!r.isHomeActivity() || mService.mHomeProcess != r.app) { + if (!r.isHomeActivity() || !mService.mHomeProcess.contains(r.app)) { Slog.w(TAG, " Force finishing activity " + r.intent.getComponent().flattenToShortString()); finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false); diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java index 0808861..250ab4a 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -905,7 +905,7 @@ public final class ActivityStackSupervisor { r.task.taskId, r.shortComponentName); } if (r.isHomeActivity() && r.isNotResolverActivity()) { - mService.mHomeProcess = app; + mService.mHomeProcess.add(app); } mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName()); r.sleeping = false; @@ -1946,7 +1946,7 @@ public final class ActivityStackSupervisor { // makes sense to. if (r.app != null && fgApp != null && r.app != fgApp && r.lastVisibleTime > mService.mPreviousProcessVisibleTime - && r.app != mService.mHomeProcess) { + && !mService.mHomeProcess.contains(r.app)) { mService.mPreviousProcess = r.app; mService.mPreviousProcessVisibleTime = r.lastVisibleTime; } diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/java/com/android/server/connectivity/PacManager.java index defe9f0..0b68ff5 100644 --- a/services/java/com/android/server/connectivity/PacManager.java +++ b/services/java/com/android/server/connectivity/PacManager.java @@ -1,14 +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.server.connectivity; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.net.ConnectivityManager; +import android.content.ServiceConnection; import android.net.ProxyProperties; +import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -17,42 +34,26 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.net.IProxyService; +import com.android.server.IoThread; +import libcore.io.Streams; -import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.conn.params.ConnRouteParams; -import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.conn.routing.HttpRoutePlanner; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.HttpContext; - -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.InetAddress; -import java.net.ProxySelector; import java.net.URL; import java.net.URLConnection; /** * @hide */ -public class PacManager implements Runnable { - public static final int NO_ERROR = 0; - public static final int PERMISSION_DENIED = 1; - public static final String PROXY_SERVICE = "com.android.net.IProxyService"; +public class PacManager { + public static final String PROXY_PACKAGE = "com.android.pacprocessor"; + public static final String PROXY_SERVICE = "com.android.pacprocessor.PacService"; + public static final String PROXY_SERVICE_NAME = "com.android.net.IProxyService"; - private static final String TAG = "PACManager"; + private static final String TAG = "PacManager"; private static final String ACTION_PAC_REFRESH = "android.net.proxy.PAC_REFRESH"; @@ -64,31 +65,57 @@ public class PacManager implements Runnable { /** Keep these values up-to-date with ProxyService.java */ public static final String KEY_PROXY = "keyProxy"; private String mCurrentPac; - private volatile String mPacUrl; + @GuardedBy("mProxyLock") + private String mPacUrl; private AlarmManager mAlarmManager; + @GuardedBy("mProxyLock") private IProxyService mProxyService; private PendingIntent mPacRefreshIntent; + private ServiceConnection mConnection; private Context mContext; private int mCurrentDelay; + /** + * Used for locking when setting mProxyService and all references to mPacUrl or mCurrentPac. + */ + private final Object mProxyLock = new Object(); + + private Runnable mPacDownloader = new Runnable() { + @Override + public void run() { + String file; + synchronized (mProxyLock) { + if (mPacUrl == null) return; + try { + file = get(mPacUrl); + } catch (IOException ioe) { + file = null; + Log.w(TAG, "Failed to load PAC file: " + ioe); + } + } + if (file != null) { + synchronized (mProxyLock) { + if (!file.equals(mCurrentPac)) { + setCurrentProxyScript(file); + } + } + longSchedule(); + } else { + reschedule(); + } + } + }; + class PacRefreshIntentReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { - new Thread(PacManager.this).start(); + IoThread.getHandler().post(mPacDownloader); } } public PacManager(Context context) { mContext = context; - mProxyService = IProxyService.Stub.asInterface( - ServiceManager.getService(PROXY_SERVICE)); - if (mProxyService == null) { - // Added because of b10267814 where mako is restarting. - Log.e(TAG, "PacManager: no proxy service"); - } else { - Log.d(TAG, "PacManager: mProxyService available"); - } mPacRefreshIntent = PendingIntent.getBroadcast( context, 0, new Intent(ACTION_PAC_REFRESH), 0); @@ -103,26 +130,28 @@ public class PacManager implements Runnable { return mAlarmManager; } - public void setCurrentProxyScriptUrl(ProxyProperties proxy) { - if (mProxyService == null) { - Log.e(TAG, "setCurrentProxyScriptUrl: no proxy service"); - return; - } + public synchronized void setCurrentProxyScriptUrl(ProxyProperties proxy) { if (!TextUtils.isEmpty(proxy.getPacFileUrl())) { - try { - mProxyService.startPacSystem(); + synchronized (mProxyLock) { mPacUrl = proxy.getPacFileUrl(); - mCurrentDelay = DELAY_1; - getAlarmManager().cancel(mPacRefreshIntent); - new Thread(this).start(); - } catch (RemoteException e) { - Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e); } + mCurrentDelay = DELAY_1; + getAlarmManager().cancel(mPacRefreshIntent); + bind(); } else { - try { - mProxyService.stopPacSystem(); - } catch (RemoteException e) { - e.printStackTrace(); + getAlarmManager().cancel(mPacRefreshIntent); + synchronized (mProxyLock) { + mPacUrl = null; + mCurrentPac = null; + if (mProxyService != null) { + try { + mProxyService.stopPacSystem(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to stop PAC service", e); + } finally { + unbind(); + } + } } } } @@ -132,51 +161,10 @@ public class PacManager implements Runnable { * * @throws IOException */ - public static String get(String urlString) throws IOException { + private static String get(String urlString) throws IOException { URL url = new URL(urlString); URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY); - BufferedReader in = new BufferedReader(new InputStreamReader( - urlConnection.getInputStream())); - String inputLine; - String resp = ""; - while ((inputLine = in.readLine()) != null) { - resp = resp + inputLine + "\n"; - } - in.close(); - return resp; - } - - private static String toString(InputStream content) throws IOException { - StringBuffer buffer = new StringBuffer(); - String line; - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(content)); - - while ((line = bufferedReader.readLine()) != null) { - if (buffer.length() != 0) { - buffer.append('\n'); - } - buffer.append(line); - } - - return buffer.toString(); - } - - @Override - public void run() { - String file; - try { - file = get(mPacUrl); - } catch (IOException ioe) { - file = null; - } - if (file != null) { - if (!file.equals(mCurrentPac)) { - setCurrentProxyScript(file); - } - longSchedule(); - } else { - reschedule(); - } + return new String(Streams.readFully(urlConnection.getInputStream())); } private int getNextDelay(int currentDelay) { @@ -227,14 +215,60 @@ public class PacManager implements Runnable { return false; } try { - if (mProxyService.setPacFile(script) != NO_ERROR) { - Log.e(TAG, "Unable to parse proxy script."); - return false; - } + mProxyService.setPacFile(script); mCurrentPac = script; } catch (RemoteException e) { Log.e(TAG, "Unable to set PAC file", e); } return true; } + + private void bind() { + if (mContext == null) { + Log.e(TAG, "No context for binding"); + return; + } + Intent intent = new Intent(); + intent.setClassName(PROXY_PACKAGE, PROXY_SERVICE); + mConnection = new ServiceConnection() { + @Override + public void onServiceDisconnected(ComponentName component) { + synchronized (mProxyLock) { + mProxyService = null; + } + } + + @Override + public void onServiceConnected(ComponentName component, IBinder binder) { + synchronized (mProxyLock) { + try { + Log.d(TAG, "Adding service " + PROXY_SERVICE_NAME + " " + + binder.getInterfaceDescriptor()); + } catch (RemoteException e1) { + Log.e(TAG, "Remote Exception", e1); + } + ServiceManager.addService(PROXY_SERVICE_NAME, binder); + mProxyService = IProxyService.Stub.asInterface(binder); + if (mProxyService == null) { + Log.e(TAG, "No proxy service"); + } else { + try { + mProxyService.startPacSystem(); + } catch (RemoteException e) { + Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e); + } + IoThread.getHandler().post(mPacDownloader); + } + } + } + }; + Log.e(TAG, "Attempting to bind"); + mContext.bindService(intent, mConnection, + Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE); + } + + private void unbind() { + mContext.unbindService(mConnection); + mConnection = null; + } } diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java index ee5b890..a6b69a2 100644 --- a/services/java/com/android/server/content/SyncManager.java +++ b/services/java/com/android/server/content/SyncManager.java @@ -2889,11 +2889,12 @@ public class SyncManager { // determine if we need to set or cancel the alarm boolean shouldSet = false; boolean shouldCancel = false; - final boolean alarmIsActive = mAlarmScheduleTime != null; + final boolean alarmIsActive = (mAlarmScheduleTime != null) && (now < mAlarmScheduleTime); final boolean needAlarm = alarmTime != Long.MAX_VALUE; if (needAlarm) { - // Need the alarm if it's currently not set, or if our time is before the currently - // set time. + // Need the alarm if + // - it's currently not set + // - if the alarm is set in the past. if (!alarmIsActive || alarmTime < mAlarmScheduleTime) { shouldSet = true; } @@ -2910,7 +2911,7 @@ public class SyncManager { + " secs from now"); } mAlarmScheduleTime = alarmTime; - mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, + mAlarmService.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, mSyncAlarmIntent); } else if (shouldCancel) { mAlarmScheduleTime = null; diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java index 25529a6..e3693f8 100644 --- a/services/java/com/android/server/content/SyncStorageEngine.java +++ b/services/java/com/android/server/content/SyncStorageEngine.java @@ -53,6 +53,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; @@ -71,7 +72,7 @@ public class SyncStorageEngine extends Handler { private static final String TAG = "SyncManager"; private static final boolean DEBUG = true; - private static final boolean DEBUG_FILE = true; + private static final String TAG_FILE = "SyncManagerFile"; private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId"; private static final String XML_ATTR_LISTEN_FOR_TICKLES = "listen-for-tickles"; @@ -420,9 +421,12 @@ public class SyncStorageEngine extends Handler { File systemDir = new File(dataDir, "system"); File syncDir = new File(systemDir, "sync"); syncDir.mkdirs(); + + maybeDeleteLegacyPendingInfoLocked(syncDir); + mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); mStatusFile = new AtomicFile(new File(syncDir, "status.bin")); - mPendingFile = new AtomicFile(new File(syncDir, "pending.bin")); + mPendingFile = new AtomicFile(new File(syncDir, "pending.xml")); mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin")); readAccountInfoLocked(); @@ -676,7 +680,8 @@ public class SyncStorageEngine extends Handler { continue; } for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) { - if (providerName != null && !providerName.equals(authorityInfo.authority)) { + if (providerName != null + && !providerName.equals(authorityInfo.authority)) { continue; } if (authorityInfo.backoffTime != nextSyncTime @@ -774,10 +779,12 @@ public class SyncStorageEngine extends Handler { } synchronized (mAuthorities) { if (toUpdate.period <= 0 && add) { - Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + add); + Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + + add); } if (toUpdate.extras == null) { - Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + add); + Log.e(TAG, "null extras, should never happen in updateOrRemovePeriodicSync: add-" + + add); } try { AuthorityInfo authority = @@ -806,7 +813,7 @@ public class SyncStorageEngine extends Handler { if (!alreadyPresent) { authority.periodicSyncs.add(new PeriodicSync(toUpdate)); SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident); - status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0); + status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0L); } } else { // Remove any periodic syncs that match the authority and extras. @@ -824,7 +831,8 @@ public class SyncStorageEngine extends Handler { if (status != null) { status.removePeriodicSyncTime(i); } else { - Log.e(TAG, "Tried removing sync status on remove periodic sync but did not find it."); + Log.e(TAG, "Tried removing sync status on remove periodic sync but" + + "did not find it."); } } else { i++; @@ -942,7 +950,7 @@ public class SyncStorageEngine extends Handler { op = new PendingOperation(op); op.authorityId = authority.ident; mPendingOperations.add(op); - writePendingOperationsLocked(); + appendPendingOperationLocked(op); SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident); status.pending = true; @@ -1660,7 +1668,9 @@ public class SyncStorageEngine extends Handler { FileInputStream fis = null; try { fis = mAccountInfoFile.openRead(); - if (DEBUG_FILE) Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile()); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile()); + } XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, null); int eventType = parser.getEventType(); @@ -1745,6 +1755,20 @@ public class SyncStorageEngine extends Handler { } /** + * Ensure the old pending.bin is deleted, as it has been changed to pending.xml. + * pending.xml was used starting in KLP. + * @param syncDir directory where the sync files are located. + */ + private void maybeDeleteLegacyPendingInfoLocked(File syncDir) { + File file = new File(syncDir, "pending.bin"); + if (!file.exists()) { + return; + } else { + file.delete(); + } + } + + /** * some authority names have changed. copy over their settings and delete the old ones * @return true if a change was made */ @@ -1832,18 +1856,21 @@ public class SyncStorageEngine extends Handler { syncable = "unknown"; } authority = mAuthorities.get(id); - if (DEBUG_FILE) Log.v(TAG, "Adding authority: account=" - + accountName + " auth=" + authorityName - + " user=" + userId - + " enabled=" + enabled - + " syncable=" + syncable); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Adding authority: account=" + + accountName + " auth=" + authorityName + + " user=" + userId + + " enabled=" + enabled + + " syncable=" + syncable); + } if (authority == null) { - if (DEBUG_FILE) { + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { Log.v(TAG, "Creating entry"); } if (accountName != null && accountType != null) { authority = getOrCreateAuthorityLocked( - new Account(accountName, accountType), userId, authorityName, id, false); + new Account(accountName, accountType), userId, authorityName, id, + false); } else { authority = getOrCreateAuthorityLocked( new ComponentName(packageName, className), userId, id, false); @@ -1943,7 +1970,9 @@ public class SyncStorageEngine extends Handler { * Write all account information to the account file. */ private void writeAccountInfoLocked() { - if (DEBUG_FILE) Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile()); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile()); + } FileOutputStream fos = null; try { @@ -2041,7 +2070,9 @@ public class SyncStorageEngine extends Handler { final boolean hasType = db.getVersion() >= 11; // Copy in all of the status information, as well as accounts. - if (DEBUG_FILE) Log.v(TAG, "Reading legacy sync accounts db"); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Reading legacy sync accounts db"); + } SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables("stats, status"); HashMap<String,String> map = new HashMap<String,String>(); @@ -2151,7 +2182,9 @@ public class SyncStorageEngine extends Handler { * Read all sync status back in to the initial engine state. */ private void readStatusLocked() { - if (DEBUG_FILE) Log.v(TAG, "Reading " + mStatusFile.getBaseFile()); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Reading " + mStatusFile.getBaseFile()); + } try { byte[] data = mStatusFile.readFully(); Parcel in = Parcel.obtain(); @@ -2163,8 +2196,10 @@ public class SyncStorageEngine extends Handler { SyncStatusInfo status = new SyncStatusInfo(in); if (mAuthorities.indexOfKey(status.authorityId) >= 0) { status.pending = false; - if (DEBUG_FILE) Log.v(TAG, "Adding status for id " - + status.authorityId); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Adding status for id " + + status.authorityId); + } mSyncStatus.put(status.authorityId, status); } } else { @@ -2182,7 +2217,9 @@ public class SyncStorageEngine extends Handler { * Write all sync status to the sync status file. */ private void writeStatusLocked() { - if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatusFile.getBaseFile()); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Writing new " + mStatusFile.getBaseFile()); + } // The file is being written, so we don't need to have a scheduled // write until the next change. @@ -2211,103 +2248,97 @@ public class SyncStorageEngine extends Handler { } } - public static final int PENDING_OPERATION_VERSION = 4; + public static final int PENDING_OPERATION_VERSION = 3; - /** - * Read all pending operations back in to the initial engine state. - */ + /** Read all pending operations back in to the initial engine state. */ private void readPendingOperationsLocked() { - if (DEBUG_FILE) Log.v(TAG, "Reading " + mPendingFile.getBaseFile()); - try { - readPendingAsXml(); - } catch (XmlPullParserException e) { - Log.d(TAG, "Error parsing pending as xml, trying as parcel."); - try { - readPendingAsParcelled(); - } catch (java.io.IOException e1) { - Log.i(TAG, "No initial pending operations"); + FileInputStream fis = null; + if (!mPendingFile.getBaseFile().exists()) { + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG_FILE, "No pending operation file."); + return; } } - } - - private void readPendingAsXml() throws XmlPullParserException { - FileInputStream fis = null; try { fis = mPendingFile.openRead(); - XmlPullParser parser = Xml.newPullParser(); + XmlPullParser parser; + parser = Xml.newPullParser(); parser.setInput(fis, null); + int eventType = parser.getEventType(); while (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_DOCUMENT) { eventType = parser.next(); } - if (eventType == XmlPullParser.END_DOCUMENT) return; + if (eventType == XmlPullParser.END_DOCUMENT) return; // Nothing to read. String tagName = parser.getName(); - if ("pending".equals(tagName)) { - int version = -1; - String versionString = parser.getAttributeValue(null, "version"); - if (versionString == null || - Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) { - Log.w(TAG, "Unknown pending operation version " - + version + "; trying to read as binary."); - throw new XmlPullParserException("Unknown version."); - } - eventType = parser.next(); + do { PendingOperation pop = null; - do { - if (eventType == XmlPullParser.START_TAG) { - try { - tagName = parser.getName(); - if (parser.getDepth() == 2 && "op".equals(tagName)) { - int authorityId = Integer.valueOf(parser.getAttributeValue( - null, XML_ATTR_AUTHORITYID)); - boolean expedited = Boolean.valueOf(parser.getAttributeValue( - null, XML_ATTR_EXPEDITED)); - int syncSource = Integer.valueOf(parser.getAttributeValue( - null, XML_ATTR_SOURCE)); - int reason = Integer.valueOf(parser.getAttributeValue( - null, XML_ATTR_REASON)); - AuthorityInfo authority = mAuthorities.get(authorityId); - if (DEBUG_FILE) { - Log.v(TAG, authorityId + " " + expedited + " " + syncSource + " " + reason); - } - if (authority != null) { - pop = new PendingOperation( - authority.account, authority.userId, reason, syncSource, - authority.authority, new Bundle(), expedited); - pop.authorityId = authorityId; - pop.flatExtras = null; // No longer used. - mPendingOperations.add(pop); - if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + pop.account - + " auth=" + pop.authority + if (eventType == XmlPullParser.START_TAG) { + try { + tagName = parser.getName(); + if (parser.getDepth() == 1 && "op".equals(tagName)) { + // Verify version. + String versionString = + parser.getAttributeValue(null, XML_ATTR_VERSION); + if (versionString == null || + Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) { + Log.w(TAG, "Unknown pending operation version " + versionString); + throw new java.io.IOException("Unknown version."); + } + int authorityId = Integer.valueOf(parser.getAttributeValue( + null, XML_ATTR_AUTHORITYID)); + boolean expedited = Boolean.valueOf(parser.getAttributeValue( + null, XML_ATTR_EXPEDITED)); + int syncSource = Integer.valueOf(parser.getAttributeValue( + null, XML_ATTR_SOURCE)); + int reason = Integer.valueOf(parser.getAttributeValue( + null, XML_ATTR_REASON)); + AuthorityInfo authority = mAuthorities.get(authorityId); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG_FILE, authorityId + " " + expedited + " " + syncSource + " " + + reason); + } + if (authority != null) { + pop = new PendingOperation( + authority.account, authority.userId, reason, + syncSource, authority.authority, new Bundle(), + expedited); + pop.flatExtras = null; // No longer used. + mPendingOperations.add(pop); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG_FILE, "Adding pending op: " + + pop.authority + " src=" + pop.syncSource + " reason=" + pop.reason + " expedited=" + pop.expedited); - } else { - // Skip non-existent authority; - pop = null; - if (DEBUG_FILE) { - Log.v(TAG, "No authority found for " + authorityId - + ", skipping"); - } } - } else if (parser.getDepth() == 3 && - pop != null && - "extra".equals(tagName)) { - parseExtra(parser, pop.extras); + } else { + // Skip non-existent authority. + pop = null; + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG_FILE, "No authority found for " + authorityId + + ", skipping"); + } } - } catch (NumberFormatException e) { - Log.d(TAG, "Invalid data in xml file.", e); + } else if (parser.getDepth() == 2 && + pop != null && + "extra".equals(tagName)) { + parseExtra(parser, pop.extras); } + } catch (NumberFormatException e) { + Log.d(TAG, "Invalid data in xml file.", e); } - eventType = parser.next(); - } while(eventType != XmlPullParser.END_DOCUMENT); - } + } + eventType = parser.next(); + } while(eventType != XmlPullParser.END_DOCUMENT); } catch (java.io.IOException e) { - if (fis == null) Log.i(TAG, "No initial pending operations."); - else Log.w(TAG, "Error reading pending data.", e); - return; + Log.w(TAG_FILE, "Error reading pending data.", e); + } catch (XmlPullParserException e) { + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.w(TAG_FILE, "Error parsing pending ops xml.", e); + } } finally { if (fis != null) { try { @@ -2316,60 +2347,99 @@ public class SyncStorageEngine extends Handler { } } } + + private static final String XML_ATTR_AUTHORITYID = "authority_id"; + private static final String XML_ATTR_SOURCE = "source"; + private static final String XML_ATTR_EXPEDITED = "expedited"; + private static final String XML_ATTR_REASON = "reason"; + private static final String XML_ATTR_VERSION = "version"; + /** - * Old format of reading pending.bin as a parcelled file. Replaced in lieu of JSON because - * persisting parcels is unsafe. - * @throws java.io.IOException + * Write all currently pending ops to the pending ops file. */ - private void readPendingAsParcelled() throws java.io.IOException { - byte[] data = mPendingFile.readFully(); - Parcel in = Parcel.obtain(); - in.unmarshall(data, 0, data.length); - in.setDataPosition(0); - final int SIZE = in.dataSize(); - while (in.dataPosition() < SIZE) { - int version = in.readInt(); - if (version != 3 && version != 1) { - Log.w(TAG, "Unknown pending operation version " - + version + "; dropping all ops"); - break; - } - int authorityId = in.readInt(); - int syncSource = in.readInt(); - byte[] flatExtras = in.createByteArray(); - boolean expedited; - if (version == PENDING_OPERATION_VERSION) { - expedited = in.readInt() != 0; - } else { - expedited = false; - } - int reason = in.readInt(); - AuthorityInfo authority = mAuthorities.get(authorityId); - if (authority != null) { - Bundle extras; - if (flatExtras != null) { - extras = unflattenBundle(flatExtras); - } else { - // if we are unable to parse the extras for whatever reason convert this - // to a regular sync by creating an empty extras - extras = new Bundle(); + private void writePendingOperationsLocked() { + final int N = mPendingOperations.size(); + FileOutputStream fos = null; + try { + if (N == 0) { + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG_FILE, "Truncating " + mPendingFile.getBaseFile()); } - PendingOperation op = new PendingOperation( - authority.account, authority.userId, reason, syncSource, - authority.authority, extras, expedited); - op.authorityId = authorityId; - op.flatExtras = flatExtras; - if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + op.account - + " auth=" + op.authority - + " src=" + op.syncSource - + " reason=" + op.reason - + " expedited=" + op.expedited - + " extras=" + op.extras); - mPendingOperations.add(op); + mPendingFile.truncate(); + return; + } + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG_FILE, "Writing new " + mPendingFile.getBaseFile()); + } + fos = mPendingFile.startWrite(); + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, "utf-8"); + + for (int i = 0; i < N; i++) { + PendingOperation pop = mPendingOperations.get(i); + writePendingOperationLocked(pop, out); + } + out.endDocument(); + mPendingFile.finishWrite(fos); + } catch (java.io.IOException e1) { + Log.w(TAG, "Error writing pending operations", e1); + if (fos != null) { + mPendingFile.failWrite(fos); } } } + /** Write all currently pending ops to the pending ops file. */ + private void writePendingOperationLocked(PendingOperation pop, XmlSerializer out) + throws IOException { + // Pending operation. + out.startTag(null, "op"); + + out.attribute(null, XML_ATTR_VERSION, Integer.toString(PENDING_OPERATION_VERSION)); + out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId)); + out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource)); + out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited)); + out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason)); + extrasToXml(out, pop.extras); + + out.endTag(null, "op"); + } + + /** + * Append the given operation to the pending ops file; if unable to, + * write all pending ops. + */ + private void appendPendingOperationLocked(PendingOperation op) { + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Appending to " + mPendingFile.getBaseFile()); + } + FileOutputStream fos = null; + try { + fos = mPendingFile.openAppend(); + } catch (java.io.IOException e) { + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Failed append; writing full file"); + } + writePendingOperationsLocked(); + return; + } + + try { + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, "utf-8"); + writePendingOperationLocked(op, out); + out.endDocument(); + mPendingFile.finishWrite(fos); + } catch (java.io.IOException e1) { + Log.w(TAG, "Error writing appending operation", e1); + mPendingFile.failWrite(fos); + } finally { + try { + fos.close(); + } catch (IOException e) {} + } + } + static private byte[] flattenBundle(Bundle bundle) { byte[] flatData = null; Parcel parcel = Parcel.obtain(); @@ -2399,54 +2469,6 @@ public class SyncStorageEngine extends Handler { return bundle; } - private static final String XML_ATTR_AUTHORITYID = "authority_id"; - private static final String XML_ATTR_SOURCE = "source"; - private static final String XML_ATTR_EXPEDITED = "expedited"; - private static final String XML_ATTR_REASON = "reason"; - /** - * Write all currently pending ops to the pending ops file. TODO: Change this from xml - * so that we can append to this file as before. - */ - private void writePendingOperationsLocked() { - final int N = mPendingOperations.size(); - FileOutputStream fos = null; - try { - if (N == 0) { - if (DEBUG_FILE) Log.v(TAG, "Truncating " + mPendingFile.getBaseFile()); - mPendingFile.truncate(); - return; - } - if (DEBUG_FILE) Log.v(TAG, "Writing new " + mPendingFile.getBaseFile()); - fos = mPendingFile.startWrite(); - XmlSerializer out = new FastXmlSerializer(); - out.setOutput(fos, "utf-8"); - out.startDocument(null, true); - out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - - out.startTag(null, "pending"); - out.attribute(null, "version", Integer.toString(PENDING_OPERATION_VERSION)); - - for (int i = 0; i < N; i++) { - PendingOperation pop = mPendingOperations.get(i); - out.startTag(null, "op"); - out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId)); - out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource)); - out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited)); - out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason)); - extrasToXml(out, pop.extras); - out.endTag(null, "op"); - } - out.endTag(null, "pending"); - out.endDocument(); - mPendingFile.finishWrite(fos); - } catch (java.io.IOException e1) { - Log.w(TAG, "Error writing pending operations", e1); - if (fos != null) { - mPendingFile.failWrite(fos); - } - } - } - private void extrasToXml(XmlSerializer out, Bundle extras) throws java.io.IOException { for (String key : extras.keySet()) { out.startTag(null, "extra"); @@ -2479,35 +2501,6 @@ public class SyncStorageEngine extends Handler { } } -// /** -// * Update the pending ops file, if e -// */ -// private void appendPendingOperationLocked(PendingOperation op) { -// if (DEBUG_FILE) Log.v(TAG, "Appending to " + mPendingFile.getBaseFile()); -// FileOutputStream fos = null; -// try { -// fos = mPendingFile.openAppend(); -// } catch (java.io.IOException e) { -// if (DEBUG_FILE) Log.v(TAG, "Failed append; writing full file"); -// writePendingOperationsLocked(); -// return; -// } -// -// try { -// Parcel out = Parcel.obtain(); -// writePendingOperationLocked(op, out); -// fos.write(out.marshall()); -// out.recycle(); -// } catch (java.io.IOException e1) { -// Log.w(TAG, "Error writing pending operations", e1); -// } finally { -// try { -// fos.close(); -// } catch (java.io.IOException e2) { -// } -// } -// } - private void requestSync(Account account, int userId, int reason, String authority, Bundle extras) { // If this is happening in the system process, then call the syncrequest listener @@ -2568,7 +2561,9 @@ public class SyncStorageEngine extends Handler { * Write all sync statistics to the sync status file. */ private void writeStatisticsLocked() { - if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatisticsFile.getBaseFile()); + if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { + Log.v(TAG, "Writing new " + mStatisticsFile.getBaseFile()); + } // The file is being written, so we don't need to have a scheduled // write until the next change. @@ -2611,7 +2606,7 @@ public class SyncStorageEngine extends Handler { sb.append("Pending Ops: ").append(mPendingOperations.size()).append(" operation(s)\n"); for (PendingOperation pop : mPendingOperations) { sb.append("(" + pop.account) - .append(", " + pop.userId) + .append(", u" + pop.userId) .append(", " + pop.authority) .append(", " + pop.extras) .append(")\n"); diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java index f89917c..846a74d 100644 --- a/services/java/com/android/server/display/WifiDisplayController.java +++ b/services/java/com/android/server/display/WifiDisplayController.java @@ -83,11 +83,6 @@ final class WifiDisplayController implements DumpUtils.Dump { private static final int CONNECT_MAX_RETRIES = 3; private static final int CONNECT_RETRY_DELAY_MILLIS = 500; - // A unique token to identify the remote submix that is managed by Wifi display. - // It must match what the media server uses when it starts recording the submix - // for transmission. We use 0 although the actual value is currently ignored. - private static final int REMOTE_SUBMIX_ADDRESS = 0; - private final Context mContext; private final Handler mHandler; private final Listener mListener; @@ -95,8 +90,6 @@ final class WifiDisplayController implements DumpUtils.Dump { private final WifiP2pManager mWifiP2pManager; private final Channel mWifiP2pChannel; - private final AudioManager mAudioManager; - private boolean mWifiP2pEnabled; private boolean mWfdEnabled; private boolean mWfdEnabling; @@ -146,9 +139,6 @@ final class WifiDisplayController implements DumpUtils.Dump { // True if RTSP has connected. private boolean mRemoteDisplayConnected; - // True if the remote submix is enabled. - private boolean mRemoteSubmixOn; - // The information we have most recently told WifiDisplayAdapter about. private WifiDisplay mAdvertisedDisplay; private Surface mAdvertisedDisplaySurface; @@ -164,8 +154,6 @@ final class WifiDisplayController implements DumpUtils.Dump { mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE); mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null); - mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); - IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); @@ -211,7 +199,6 @@ final class WifiDisplayController implements DumpUtils.Dump { pw.println("mRemoteDisplay=" + mRemoteDisplay); pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface); pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected); - pw.println("mRemoteSubmixOn=" + mRemoteSubmixOn); pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay); pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface); pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth); @@ -482,7 +469,6 @@ final class WifiDisplayController implements DumpUtils.Dump { mHandler.removeCallbacks(mRtspTimeout); mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED); - setRemoteSubmixOn(false); unadvertiseDisplay(); // continue to next step @@ -626,7 +612,6 @@ final class WifiDisplayController implements DumpUtils.Dump { return; // done } - setRemoteSubmixOn(true); mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE); final WifiP2pDevice oldDevice = mConnectedDevice; @@ -677,13 +662,6 @@ final class WifiDisplayController implements DumpUtils.Dump { } } - private void setRemoteSubmixOn(boolean on) { - if (mRemoteSubmixOn != on) { - mRemoteSubmixOn = on; - mAudioManager.setRemoteSubmixOn(on, REMOTE_SUBMIX_ADDRESS); - } - } - private void handleStateChanged(boolean enabled) { mWifiP2pEnabled = enabled; updateWfdEnableState(); diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java index 21e54fe..b6e7781 100644 --- a/services/java/com/android/server/dreams/DreamManagerService.java +++ b/services/java/com/android/server/dreams/DreamManagerService.java @@ -86,7 +86,13 @@ public final class DreamManagerService extends IDreamManager.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + if (mContext.checkCallingOrSelfPermission("android.permission.DUMP") + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump DreamManager from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } pw.println("DREAM MANAGER (dumpsys dreams)"); pw.println(); diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java index 226c18c..ebeccfb 100644 --- a/services/java/com/android/server/location/FlpHardwareProvider.java +++ b/services/java/com/android/server/location/FlpHardwareProvider.java @@ -16,12 +16,13 @@ package com.android.server.location; +import android.hardware.location.GeofenceHardware; import android.hardware.location.GeofenceHardwareImpl; +import android.hardware.location.GeofenceHardwareRequestParcelable; 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; @@ -49,6 +50,15 @@ public class FlpHardwareProvider { private final Context mContext; private final Object mLocationSinkLock = new Object(); + // FlpHal result codes, they must be equal to the ones in fused_location.h + private static final int FLP_RESULT_SUCCESS = 0; + private static final int FLP_RESULT_ERROR = -1; + private static final int FLP_RESULT_INSUFFICIENT_MEMORY = -2; + private static final int FLP_RESULT_TOO_MANY_GEOFENCES = -3; + private static final int FLP_RESULT_ID_EXISTS = -4; + private static final int FLP_RESULT_ID_UNKNOWN = -5; + private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6; + public static FlpHardwareProvider getInstance(Context context) { if (sSingletonInstance == null) { sSingletonInstance = new FlpHardwareProvider(context); @@ -120,29 +130,46 @@ public class FlpHardwareProvider { Location location, int transition, long timestamp, - int sourcesUsed - ) { - // TODO: [GeofenceIntegration] change GeofenceHardwareImpl to accept a location object + int sourcesUsed) { + getGeofenceHardwareSink().reportGeofenceTransition( + geofenceId, + updateLocationInformation(location), + transition, + timestamp, + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, + sourcesUsed); } private void onGeofenceMonitorStatus(int status, int source, Location location) { - // TODO: [GeofenceIntegration] + getGeofenceHardwareSink().reportGeofenceMonitorStatus( + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, + status, + updateLocationInformation(location), + source); } private void onGeofenceAdd(int geofenceId, int result) { - // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status + getGeofenceHardwareSink().reportGeofenceAddStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); } private void onGeofenceRemove(int geofenceId, int result) { - // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status + getGeofenceHardwareSink().reportGeofenceRemoveStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); } private void onGeofencePause(int geofenceId, int result) { - // TODO; [GeofenceIntegration] map between GPS and FLP results + getGeofenceHardwareSink().reportGeofencePauseStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); } private void onGeofenceResume(int geofenceId, int result) { - // TODO: [GeofenceIntegration] map between GPS and FLP results + getGeofenceHardwareSink().reportGeofenceResumeStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); } /** @@ -175,7 +202,8 @@ public class FlpHardwareProvider { // FlpGeofencingInterface members private native boolean nativeIsGeofencingSupported(); - private native void nativeAddGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray); + private native void nativeAddGeofences( + GeofenceHardwareRequestParcelable[] geofenceRequestsArray); private native void nativePauseGeofence(int geofenceId); private native void nativeResumeGeofence(int geofenceId, int monitorTransitions); private native void nativeModifyGeofenceOption( @@ -281,8 +309,8 @@ public class FlpHardwareProvider { } @Override - public void addGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray) { - nativeAddGeofences(geofenceIdsArray, geofencesArray); + public void addGeofences(GeofenceHardwareRequestParcelable[] geofenceRequestsArray) { + nativeAddGeofences(geofenceRequestsArray); } @Override @@ -305,17 +333,15 @@ public class FlpHardwareProvider { int lastTransition, int monitorTransitions, int notificationResponsiveness, - int unknownTimer - ) { - // TODO: [GeofenceIntegration] set sourcesToUse to the right value - // TODO: expose sourcesToUse externally when needed + int unknownTimer, + int sourcesToUse) { nativeModifyGeofenceOption( geofenceId, lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer, - /* sourcesToUse */ 0xFFFF); + sourcesToUse); } }; @@ -347,10 +373,39 @@ public class FlpHardwareProvider { 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 + + private static int translateToGeofenceHardwareStatus(int flpHalResult) { + switch(flpHalResult) { + case FLP_RESULT_SUCCESS: + return GeofenceHardware.GEOFENCE_SUCCESS; + case FLP_RESULT_ERROR: + return GeofenceHardware.GEOFENCE_FAILURE; + // TODO: uncomment this once the ERROR definition is marked public + //case FLP_RESULT_INSUFFICIENT_MEMORY: + // return GeofenceHardware.GEOFENCE_ERROR_INSUFFICIENT_MEMORY; + case FLP_RESULT_TOO_MANY_GEOFENCES: + return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; + case FLP_RESULT_ID_EXISTS: + return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; + case FLP_RESULT_ID_UNKNOWN: + return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; + case FLP_RESULT_INVALID_GEOFENCE_TRANSITION: + return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; + default: + Log.e(TAG, String.format("Invalid FlpHal result code: %d", flpHalResult)); + return GeofenceHardware.GEOFENCE_FAILURE; + } + } + + private Location updateLocationInformation(Location location) { + location.setProvider(LocationManager.FUSED_PROVIDER); + // set the elapsed time-stamp just as GPS provider does + location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + return location; + } +} diff --git a/services/java/com/android/server/location/GeofenceProxy.java b/services/java/com/android/server/location/GeofenceProxy.java index f6be27b..a86c923 100644 --- a/services/java/com/android/server/location/GeofenceProxy.java +++ b/services/java/com/android/server/location/GeofenceProxy.java @@ -22,6 +22,7 @@ import android.hardware.location.GeofenceHardwareService; import android.hardware.location.IGeofenceHardware; import android.location.IGeofenceProvider; import android.location.IGpsGeofenceHardware; +import android.location.IFusedGeofenceHardware; import android.content.Context; import android.os.Handler; import android.os.IBinder; @@ -44,6 +45,7 @@ public final class GeofenceProxy { private Context mContext; private IGeofenceHardware mGeofenceHardware; private IGpsGeofenceHardware mGpsGeofenceHardware; + private IFusedGeofenceHardware mFusedGeofenceHardware; private static final int GEOFENCE_PROVIDER_CONNECTED = 1; private static final int GEOFENCE_HARDWARE_CONNECTED = 2; @@ -60,9 +62,11 @@ public final class GeofenceProxy { public static GeofenceProxy createAndBind(Context context, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) { + int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence, + IFusedGeofenceHardware fusedGeofenceHardware) { GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence); + defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence, + fusedGeofenceHardware); if (proxy.bindGeofenceProvider()) { return proxy; } else { @@ -72,11 +76,13 @@ public final class GeofenceProxy { private GeofenceProxy(Context context, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) { + int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence, + IFusedGeofenceHardware fusedGeofenceHardware) { mContext = context; mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler); mGpsGeofenceHardware = gpsGeofence; + mFusedGeofenceHardware = fusedGeofenceHardware; bindHardwareGeofence(); } @@ -123,6 +129,13 @@ public final class GeofenceProxy { } } + private void setFusedGeofence() { + try { + mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware); + } catch(RemoteException e) { + Log.e(TAG, "Error while connecting to GeofenceHardwareService"); + } + } // This needs to be reworked, when more services get added, // Might need a state machine or add a framework utility class, @@ -142,6 +155,7 @@ public final class GeofenceProxy { break; case GEOFENCE_HARDWARE_CONNECTED: setGpsGeofence(); + setFusedGeofence(); mGeofenceHardwareConnected = true; if (mGeofenceProviderConnected) { setGeofenceHardwareInProvider(); diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 38453c8..6053c61 100644 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -24,9 +24,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; +import android.hardware.location.GeofenceHardware; import android.hardware.location.GeofenceHardwareImpl; -import android.hardware.location.IGeofenceHardware; import android.location.Criteria; +import android.location.FusedBatchOptions; import android.location.IGpsGeofenceHardware; import android.location.IGpsStatusListener; import android.location.IGpsStatusProvider; @@ -195,6 +196,17 @@ public class GpsLocationProvider implements LocationProviderInterface { private static final String PROPERTIES_FILE = "/etc/gps.conf"; + private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L; + private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L; + + // GPS Geofence errors. Should match gps.h constants. + private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0; + private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100; + private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101; + private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102; + private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103; + private static final int GPS_GEOFENCE_ERROR_GENERIC = -149; + /** simpler wrapper for ProviderRequest + Worksource */ private static class GpsRequest { public ProviderRequest request; @@ -501,7 +513,7 @@ public class GpsLocationProvider implements LocationProviderInterface { LocationManager locManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, - 0, 0, new NetworkLocationListener(), mHandler.getLooper()); + 0, 0, new NetworkLocationListener(), mHandler.getLooper()); } }); } @@ -1405,6 +1417,62 @@ public class GpsLocationProvider implements LocationProviderInterface { } /** + * Helper method to construct a location object. + */ + private Location buildLocation( + int flags, + double latitude, + double longitude, + double altitude, + float speed, + float bearing, + float accuracy, + long timestamp) { + Location location = new Location(LocationManager.GPS_PROVIDER); + if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { + location.setLatitude(latitude); + location.setLongitude(longitude); + location.setTime(timestamp); + location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + } + if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { + location.setAltitude(altitude); + } + if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { + location.setSpeed(speed); + } + if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { + location.setBearing(bearing); + } + if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { + location.setAccuracy(accuracy); + } + return location; + } + + /** + * Converts the GPS HAL status to the internal Geofence Hardware status. + */ + private int getGeofenceStatus(int status) { + switch(status) { + case GPS_GEOFENCE_OPERATION_SUCCESS: + return GeofenceHardware.GEOFENCE_SUCCESS; + case GPS_GEOFENCE_ERROR_GENERIC: + return GeofenceHardware.GEOFENCE_FAILURE; + case GPS_GEOFENCE_ERROR_ID_EXISTS: + return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; + case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: + return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; + case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: + return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; + case GPS_GEOFENCE_ERROR_ID_UNKNOWN: + return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; + default: + return -1; + } + } + + /** * Called from native to report GPS Geofence transition * All geofence callbacks are called on the same thread */ @@ -1414,8 +1482,22 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceTransition(geofenceId, flags, latitude, longitude, - altitude, speed, bearing, accuracy, timestamp, transition, transitionTimestamp); + Location location = buildLocation( + flags, + latitude, + longitude, + altitude, + speed, + bearing, + accuracy, + timestamp); + mGeofenceHardwareImpl.reportGeofenceTransition( + geofenceId, + location, + transition, + transitionTimestamp, + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + FusedBatchOptions.SourceTechnologies.GNSS); } /** @@ -1427,8 +1509,24 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceStatus(status, flags, latitude, longitude, altitude, - speed, bearing, accuracy, timestamp); + Location location = buildLocation( + flags, + latitude, + longitude, + altitude, + speed, + bearing, + accuracy, + timestamp); + int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; + if(status == GPS_GEOFENCE_AVAILABLE) { + monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; + } + mGeofenceHardwareImpl.reportGeofenceMonitorStatus( + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + monitorStatus, + location, + FusedBatchOptions.SourceTechnologies.GNSS); } /** @@ -1438,7 +1536,7 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceAddStatus(geofenceId, status); + mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); } /** @@ -1448,7 +1546,7 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceRemoveStatus(geofenceId, status); + mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); } /** @@ -1458,7 +1556,7 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofencePauseStatus(geofenceId, status); + mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); } /** @@ -1468,7 +1566,7 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceResumeStatus(geofenceId, status); + mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); } //============================================================= diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 656080b..78c1c79 100755 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -1792,8 +1792,8 @@ public class PackageManagerService extends IPackageManager.Stub { } } + @Override public int[] getPackageGids(String packageName) { - final boolean enforcedDefault = isPermissionEnforcedDefault(READ_EXTERNAL_STORAGE); // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1801,17 +1801,7 @@ public class PackageManagerService extends IPackageManager.Stub { Log.v(TAG, "getPackageGids" + packageName + ": " + p); if (p != null) { final PackageSetting ps = (PackageSetting)p.mExtras; - final SharedUserSetting suid = ps.sharedUser; - int[] gids = suid != null ? suid.gids : ps.gids; - - // include GIDs for any unenforced permissions - if (!isPermissionEnforcedLocked(READ_EXTERNAL_STORAGE, enforcedDefault)) { - final BasePermission basePerm = mSettings.mPermissions.get( - READ_EXTERNAL_STORAGE); - gids = appendInts(gids, basePerm.gids); - } - - return gids; + return ps.getGids(); } } // stupid thing to indicate an error. @@ -2132,7 +2122,6 @@ public class PackageManagerService extends IPackageManager.Stub { } public int checkPermission(String permName, String pkgName) { - final boolean enforcedDefault = isPermissionEnforcedDefault(permName); synchronized (mPackages) { PackageParser.Package p = mPackages.get(pkgName); if (p != null && p.mExtras != null) { @@ -2145,15 +2134,11 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.PERMISSION_GRANTED; } } - if (!isPermissionEnforcedLocked(permName, enforcedDefault)) { - return PackageManager.PERMISSION_GRANTED; - } } return PackageManager.PERMISSION_DENIED; } public int checkUidPermission(String permName, int uid) { - final boolean enforcedDefault = isPermissionEnforcedDefault(permName); synchronized (mPackages) { Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); if (obj != null) { @@ -2167,9 +2152,6 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.PERMISSION_GRANTED; } } - if (!isPermissionEnforcedLocked(permName, enforcedDefault)) { - return PackageManager.PERMISSION_GRANTED; - } } return PackageManager.PERMISSION_DENIED; } @@ -11112,42 +11094,9 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override + @Deprecated public boolean isPermissionEnforced(String permission) { - final boolean enforcedDefault = isPermissionEnforcedDefault(permission); - synchronized (mPackages) { - return isPermissionEnforcedLocked(permission, enforcedDefault); - } - } - - /** - * Check if given permission should be enforced by default. Should always be - * called outside of {@link #mPackages} lock. - */ - private boolean isPermissionEnforcedDefault(String permission) { - if (READ_EXTERNAL_STORAGE.equals(permission)) { - return android.provider.Settings.Global.getInt(mContext.getContentResolver(), - android.provider.Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT, 0) - != 0; - } else { - return true; - } - } - - /** - * Check if user has requested that given permission be enforced, using - * given default if undefined. - */ - private boolean isPermissionEnforcedLocked(String permission, boolean enforcedDefault) { - if (READ_EXTERNAL_STORAGE.equals(permission)) { - if (mSettings.mReadExternalStorageEnforced != null) { - return mSettings.mReadExternalStorageEnforced; - } else { - // User hasn't defined; fall back to secure default - return enforcedDefault; - } - } else { - return true; - } + return true; } public boolean isStorageLow() { diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java index f7f0870..b6f9f5b 100644 --- a/services/java/com/android/server/pm/PackageSetting.java +++ b/services/java/com/android/server/pm/PackageSetting.java @@ -52,4 +52,8 @@ final class PackageSetting extends PackageSettingBase { + Integer.toHexString(System.identityHashCode(this)) + " " + name + "/" + appId + "}"; } -}
\ No newline at end of file + + public int[] getGids() { + return sharedUser != null ? sharedUser.gids : gids; + } +} diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index e78362b..e18202b 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -1385,9 +1385,10 @@ final class Settings { StringBuilder sb = new StringBuilder(); for (final PackageSetting pkg : mPackages.values()) { - ApplicationInfo ai = pkg.pkg.applicationInfo; - String dataPath = ai.dataDir; - boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + final ApplicationInfo ai = pkg.pkg.applicationInfo; + final String dataPath = ai.dataDir; + final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + final int[] gids = pkg.getGids(); // Avoid any application that has a space in its path // or that is handled by the system. @@ -1401,6 +1402,7 @@ final class Settings { // debugFlag - 0 or 1 if the package is debuggable. // dataPath - path to package's data path // seinfo - seinfo label for the app (assigned at install time) + // gids - supplementary gids this app launches with // // NOTE: We prefer not to expose all ApplicationInfo flags for now. // @@ -1417,6 +1419,16 @@ final class Settings { sb.append(dataPath); sb.append(" "); sb.append(ai.seinfo); + sb.append(" "); + if (gids != null && gids.length > 0) { + sb.append(gids[0]); + for (int i = 1; i < gids.length; i++) { + sb.append(","); + sb.append(gids[i]); + } + } else { + sb.append("none"); + } sb.append("\n"); str.write(sb.toString().getBytes()); } @@ -1425,6 +1437,7 @@ final class Settings { str.close(); journal.commit(); } catch (Exception e) { + Log.wtf(TAG, "Failed to write packages.list", e); IoUtils.closeQuietly(str); journal.rollback(); } diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java index 322de6c..5c68460 100644 --- a/services/java/com/android/server/print/RemotePrintService.java +++ b/services/java/com/android/server/print/RemotePrintService.java @@ -30,8 +30,6 @@ import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; -import android.print.IPrinterDiscoverySessionController; -import android.print.IPrinterDiscoverySessionObserver; import android.print.PrintJobInfo; import android.print.PrintManager; import android.print.PrinterId; @@ -79,6 +77,10 @@ final class RemotePrintService implements DeathRecipient { private boolean mDestroyed; + private boolean mAllPrintJobsHandled; + + private boolean mHasPrinterDiscoverySession; + public RemotePrintService(Context context, ComponentName componentName, int userId, RemotePrintSpooler spooler) { mContext = context; @@ -97,6 +99,8 @@ final class RemotePrintService implements DeathRecipient { private void handleDestroy() { throwIfDestroyed(); ensureUnbound(); + mAllPrintJobsHandled = false; + mHasPrinterDiscoverySession = false; mDestroyed = true; } @@ -110,17 +114,27 @@ final class RemotePrintService implements DeathRecipient { } private void handleBinderDied() { + mAllPrintJobsHandled = false; + mHasPrinterDiscoverySession = false; + mPendingCommands.clear(); ensureUnbound(); } private void handleOnAllPrintJobsHandled() { throwIfDestroyed(); + + mAllPrintJobsHandled = true; + if (isBound()) { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnAllPrintJobsHandled()"); } - // If bound and all the work is completed, then unbind. - ensureUnbound(); + + // If the service has a printer discovery session + // created we should not disconnect from it just yet. + if (!mHasPrinterDiscoverySession) { + ensureUnbound(); + } } } @@ -152,6 +166,9 @@ final class RemotePrintService implements DeathRecipient { private void handleOnPrintJobQueued(final PrintJobInfo printJob) { throwIfDestroyed(); + + mAllPrintJobsHandled = false; + if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -172,20 +189,18 @@ final class RemotePrintService implements DeathRecipient { } } - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer) { - mHandler.obtainMessage(MyHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION, - observer).sendToTarget(); + public void createPrinterDiscoverySession() { + mHandler.sendEmptyMessage(MyHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION); } - private void handleCreatePrinterDiscoverySession( - final IPrinterDiscoverySessionObserver observer) { + private void handleCreatePrinterDiscoverySession() { throwIfDestroyed(); if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @Override public void run() { - handleCreatePrinterDiscoverySession(observer); + handleCreatePrinterDiscoverySession(); } }); } else { @@ -193,9 +208,126 @@ final class RemotePrintService implements DeathRecipient { Slog.i(LOG_TAG, "[user: " + mUserId + "] createPrinterDiscoverySession()"); } try { - mPrintService.createPrinterDiscoverySession(observer); + mPrintService.createPrinterDiscoverySession(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error creating printer dicovery session.", re); + } + + mHasPrinterDiscoverySession = true; + } + } + + public void destroyPrinterDiscoverySession() { + mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION); + } + + private void handleDestroyPrinterDiscoverySession() { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleDestroyPrinterDiscoverySession(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] destroyPrinterDiscoverySession()"); + } + + mHasPrinterDiscoverySession = false; + + try { + mPrintService.destroyPrinterDiscoverySession(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error destroying printer dicovery session.", re); + } + + // If the service has no print jobs and no active discovery + // session anymore we should disconnect from it. + if (mAllPrintJobsHandled) { + ensureUnbound(); + } + } + } + + public void startPrinterDiscovery(List<PrinterId> priorityList) { + mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, + priorityList).sendToTarget(); + } + + private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStartPrinterDiscovery(priorityList); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] startPrinterDiscovery()"); + } + try { + mPrintService.startPrinterDiscovery(priorityList); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error starting printer dicovery.", re); + } + } + } + + public void stopPrinterDiscovery() { + mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY); + } + + private void handleStopPrinterDiscovery() { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStopPrinterDiscovery(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()"); + } + try { + mPrintService.stopPrinterDiscovery(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error stopping printer dicovery.", re); + } + } + } + + public void requestPrinterUpdate(PrinterId printerId) { + mHandler.obtainMessage(MyHandler.MSG_REQUEST_PRINTER_UPDATE, + printerId).sendToTarget(); + } + + private void handleRequestPrinterUpdate(final PrinterId printerId) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleRequestPrinterUpdate(printerId); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] requestPrinterUpdate()"); + } + try { + mPrintService.requestPrinterUpdate(printerId); } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error announcing start printer dicovery.", re); + Slog.e(LOG_TAG, "Error requesting a printer update.", re); } } } @@ -278,20 +410,47 @@ final class RemotePrintService implements DeathRecipient { } private final class MyHandler extends Handler { - public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 1; - public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 2; - public static final int MSG_ON_PRINT_JOB_QUEUED = 3; - public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 4; - public static final int MSG_DESTROY = 6; - public static final int MSG_BINDER_DIED = 7; + public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1; + public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2; + public static final int MSG_START_PRINTER_DISCOVERY = 3; + public static final int MSG_STOP_PRINTER_DISCOVERY = 4; + public static final int MSG_REQUEST_PRINTER_UPDATE = 5; + public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 6; + public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 7; + public static final int MSG_ON_PRINT_JOB_QUEUED = 8; + public static final int MSG_DESTROY = 9; + public static final int MSG_BINDER_DIED = 10; public MyHandler(Looper looper) { super(looper, null, false); } @Override + @SuppressWarnings("unchecked") public void handleMessage(Message message) { switch (message.what) { + case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { + handleCreatePrinterDiscoverySession(); + } break; + + case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: { + handleDestroyPrinterDiscoverySession(); + } break; + + case MSG_START_PRINTER_DISCOVERY: { + List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj; + handleStartPrinterDiscovery(priorityList); + } break; + + case MSG_STOP_PRINTER_DISCOVERY: { + handleStopPrinterDiscovery(); + } break; + + case MSG_REQUEST_PRINTER_UPDATE: { + PrinterId printerId = (PrinterId) message.obj; + handleRequestPrinterUpdate(printerId); + } break; + case MSG_ON_ALL_PRINT_JOBS_HANDLED: { handleOnAllPrintJobsHandled(); } break; @@ -306,13 +465,6 @@ final class RemotePrintService implements DeathRecipient { handleOnPrintJobQueued(printJob); } break; - case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { - IPrinterDiscoverySessionObserver observer = - (IPrinterDiscoverySessionObserver) message.obj; - handleCreatePrinterDiscoverySession(new SecurePrinterDiscoverySessionObserver( - mComponentName, observer)); - } break; - case MSG_DESTROY: { handleDestroy(); } break; @@ -362,7 +514,7 @@ final class RemotePrintService implements DeathRecipient { } @Override - public boolean setPrintJobState(int printJobId, int state, CharSequence error) { + public boolean setPrintJobState(int printJobId, int state, String error) { RemotePrintService service = mWeakService.get(); if (service != null) { final long identity = Binder.clearCallingIdentity(); @@ -401,79 +553,70 @@ final class RemotePrintService implements DeathRecipient { } } } - } - - private static final class SecurePrinterDiscoverySessionObserver - extends IPrinterDiscoverySessionObserver.Stub { - private final ComponentName mComponentName; - - private final IPrinterDiscoverySessionObserver mDecoratedObsever; - - public SecurePrinterDiscoverySessionObserver(ComponentName componentName, - IPrinterDiscoverySessionObserver observer) { - mComponentName = componentName; - mDecoratedObsever = observer; - } @Override public void onPrintersAdded(List<PrinterInfo> printers) { - throwIfPrinterIdsForPrinterInfoTampered(printers); - try { - mDecoratedObsever.onPrintersAdded(printers); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error delegating to onPrintersAdded", re); - } - } - - @Override - public void onPrintersUpdated(List<PrinterInfo> printers) { - throwIfPrinterIdsForPrinterInfoTampered(printers); - try { - mDecoratedObsever.onPrintersUpdated(printers); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error delegating to onPrintersUpdated.", re); + RemotePrintService service = mWeakService.get(); + if (service != null) { + throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers); + final long identity = Binder.clearCallingIdentity(); + try { + service.mSpooler.onPrintersAdded(printers); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @Override public void onPrintersRemoved(List<PrinterId> printerIds) { - throwIfPrinterIdsTampered(printerIds); - try { - mDecoratedObsever.onPrintersRemoved(printerIds); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error delegating to onPrintersRemoved", re); + RemotePrintService service = mWeakService.get(); + if (service != null) { + throwIfPrinterIdsTampered(service.mComponentName, printerIds); + final long identity = Binder.clearCallingIdentity(); + try { + service.mSpooler.onPrintersRemoved(printerIds); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @Override - public void setController(IPrinterDiscoverySessionController controller) { - try { - mDecoratedObsever.setController(controller); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error setting controller", re); + public void onPrintersUpdated(List<PrinterInfo> printers) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers); + final long identity = Binder.clearCallingIdentity(); + try { + service.mSpooler.onPrintersUpdated(printers); + } finally { + Binder.restoreCallingIdentity(identity); + } } } - private void throwIfPrinterIdsForPrinterInfoTampered( + private void throwIfPrinterIdsForPrinterInfoTampered(ComponentName serviceName, List<PrinterInfo> printerInfos) { final int printerInfoCount = printerInfos.size(); for (int i = 0; i < printerInfoCount; i++) { PrinterId printerId = printerInfos.get(i).getId(); - throwIfPrinterIdTampered(printerId); + throwIfPrinterIdTampered(serviceName, printerId); } } - private void throwIfPrinterIdsTampered(List<PrinterId> printerIds) { + private void throwIfPrinterIdsTampered(ComponentName serviceName, + List<PrinterId> printerIds) { final int printerIdCount = printerIds.size(); for (int i = 0; i < printerIdCount; i++) { PrinterId printerId = printerIds.get(i); - throwIfPrinterIdTampered(printerId); + throwIfPrinterIdTampered(serviceName, printerId); } } - private void throwIfPrinterIdTampered(PrinterId printerId) { + private void throwIfPrinterIdTampered(ComponentName serviceName, PrinterId printerId) { if (printerId == null || printerId.getServiceName() == null - || !printerId.getServiceName().equals(mComponentName)) { + || !printerId.getServiceName().equals(serviceName)) { throw new IllegalArgumentException("Invalid printer id: " + printerId); } } diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java index c932e9b..d261288 100644 --- a/services/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/java/com/android/server/print/RemotePrintSpooler.java @@ -32,9 +32,10 @@ import android.print.IPrintDocumentAdapter; import android.print.IPrintSpooler; import android.print.IPrintSpoolerCallbacks; import android.print.IPrintSpoolerClient; -import android.print.IPrinterDiscoverySessionObserver; import android.print.PrintAttributes; import android.print.PrintJobInfo; +import android.print.PrinterId; +import android.print.PrinterInfo; import android.util.Slog; import android.util.TimedRemoteCaller; @@ -92,7 +93,11 @@ final class RemotePrintSpooler { public static interface PrintSpoolerCallbacks { public void onPrintJobQueued(PrintJobInfo printJob); public void onAllPrintJobsForServiceHandled(ComponentName printService); - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer); + public void createPrinterDiscoverySession(); + public void destroyPrinterDiscoverySession(); + public void startPrinterDiscovery(List<PrinterId> priorityList); + public void stopPrinterDiscovery(); + public void requestPrinterUpdate(PrinterId printerId); } public RemotePrintSpooler(Context context, int userId, @@ -209,7 +214,7 @@ final class RemotePrintSpooler { return null; } - public final boolean setPrintJobState(int printJobId, int state, CharSequence error) { + public final boolean setPrintJobState(int printJobId, int state, String error) { throwIfCalledOnMainThread(); synchronized (mLock) { throwIfDestroyedLocked(); @@ -300,6 +305,78 @@ final class RemotePrintSpooler { } } + public final void onPrintersAdded(List<PrinterInfo> printers) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + mCanUnbind = false; + } + try { + getRemoteInstanceLazy().onPrintersAdded(printers); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error adding printers.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error adding printers.", te); + } finally { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + + "] onPrintersAdded()"); + } + synchronized (mLock) { + mCanUnbind = true; + mLock.notifyAll(); + } + } + } + + public final void onPrintersRemoved(List<PrinterId> printerIds) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + mCanUnbind = false; + } + try { + getRemoteInstanceLazy().onPrintersRemoved(printerIds); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error removing printers.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error removing printers.", te); + } finally { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + + "] onPrintersRemoved()"); + } + synchronized (mLock) { + mCanUnbind = true; + mLock.notifyAll(); + } + } + } + + public final void onPrintersUpdated(List<PrinterInfo> printers) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + mCanUnbind = false; + } + try { + getRemoteInstanceLazy().onPrintersUpdated(printers); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error updating printers.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error updating printers.", te); + } finally { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + + "] onPrintersUpdted()"); + } + synchronized (mLock) { + mCanUnbind = true; + mLock.notifyAll(); + } + } + } + private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException { synchronized (mLock) { if (mRemoteInstance != null) { @@ -488,7 +565,7 @@ final class RemotePrintSpooler { } public boolean setPrintJobState(IPrintSpooler target, int printJobId, - int status, CharSequence error) throws RemoteException, TimeoutException { + int status, String error) throws RemoteException, TimeoutException { final int sequence = onBeforeRemoteCall(); target.setPrintJobState(printJobId, status, error, mCallback, sequence); return getResultTimed(sequence); @@ -597,12 +674,64 @@ final class RemotePrintSpooler { } @Override - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer) { + public void createPrinterDiscoverySession() { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.createPrinterDiscoverySession(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void destroyPrinterDiscoverySession() { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.destroyPrinterDiscoverySession(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void startPrinterDiscovery(List<PrinterId> priorityList) { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.startPrinterDiscovery(priorityList); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void stopPrinterDiscovery() { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.stopPrinterDiscovery(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void requestPrinterUpdate(PrinterId printerId) { RemotePrintSpooler spooler = mWeakSpooler.get(); if (spooler != null) { final long identity = Binder.clearCallingIdentity(); try { - spooler.mCallbacks.createPrinterDiscoverySession(observer); + spooler.mCallbacks.requestPrinterUpdate(printerId); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index ffcc9c3..9d7cfdd 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -21,8 +21,8 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.print.IPrinterDiscoverySessionObserver; import android.print.PrintJobInfo; +import android.print.PrinterId; import android.printservice.PrintServiceInfo; import android.provider.Settings; import android.text.TextUtils; @@ -105,7 +105,7 @@ final class UserState implements PrintSpoolerCallbacks { } @Override - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer) { + public void createPrinterDiscoverySession() { final List<RemotePrintService> services; synchronized (mLock) { throwIfDestroyedLocked(); @@ -117,7 +117,73 @@ final class UserState implements PrintSpoolerCallbacks { final int serviceCount = services.size(); for (int i = 0; i < serviceCount; i++) { RemotePrintService service = services.get(i); - service.createPrinterDiscoverySession(observer); + service.createPrinterDiscoverySession(); + } + } + + @Override + public void destroyPrinterDiscoverySession() { + final List<RemotePrintService> services; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + services = new ArrayList<RemotePrintService>(mActiveServices.values()); + } + final int serviceCount = services.size(); + for (int i = 0; i < serviceCount; i++) { + RemotePrintService service = services.get(i); + service.destroyPrinterDiscoverySession(); + } + } + + @Override + public void startPrinterDiscovery(List<PrinterId> printerIds) { + final List<RemotePrintService> services; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + services = new ArrayList<RemotePrintService>(mActiveServices.values()); + } + final int serviceCount = services.size(); + for (int i = 0; i < serviceCount; i++) { + RemotePrintService service = services.get(i); + service.startPrinterDiscovery(printerIds); + } + } + + @Override + public void stopPrinterDiscovery() { + final List<RemotePrintService> services; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + services = new ArrayList<RemotePrintService>(mActiveServices.values()); + } + final int serviceCount = services.size(); + for (int i = 0; i < serviceCount; i++) { + RemotePrintService service = services.get(i); + service.stopPrinterDiscovery(); + } + } + + @Override + public void requestPrinterUpdate(PrinterId printerId) { + final RemotePrintService service; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + service = mActiveServices.get(printerId.getServiceName()); + } + if (service != null) { + service.requestPrinterUpdate(printerId); } } diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java index 6e0e055..c215f40 100644 --- a/services/java/com/android/server/wifi/WifiService.java +++ b/services/java/com/android/server/wifi/WifiService.java @@ -25,18 +25,20 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.database.ContentObserver; +import android.net.DhcpInfo; +import android.net.DhcpResults; +import android.net.LinkAddress; +import android.net.NetworkUtils; +import android.net.RouteInfo; import android.net.wifi.IWifiManager; import android.net.wifi.ScanResult; +import android.net.wifi.BatchedScanResult; +import android.net.wifi.BatchedScanSettings; +import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiStateMachine; -import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiWatchdogStateMachine; -import android.net.DhcpInfo; -import android.net.DhcpResults; -import android.net.LinkAddress; -import android.net.NetworkUtils; -import android.net.RouteInfo; import android.os.Binder; import android.os.Handler; import android.os.Messenger; @@ -63,6 +65,7 @@ import java.io.PrintWriter; import java.net.InetAddress; import java.net.Inet4Address; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -121,6 +124,8 @@ public final class WifiService extends IWifiManager.Stub { /* Tracks the persisted states for wi-fi & airplane mode */ final WifiSettingsStore mSettingsStore; + final boolean mBatchedScanSupported; + /** * Asynchronous channel to WifiStateMachine */ @@ -246,6 +251,9 @@ public final class WifiService extends IWifiManager.Stub { mWifiController = new WifiController(mContext, this, wifiThread.getLooper()); mWifiController.start(); + mBatchedScanSupported = mContext.getResources().getBoolean( + R.bool.config_wifi_batched_scan_supported); + registerForScanModeChange(); mContext.registerReceiver( new BroadcastReceiver() { @@ -314,6 +322,148 @@ public final class WifiService extends IWifiManager.Stub { mWifiStateMachine.startScan(Binder.getCallingUid(), workSource); } + private class BatchedScanRequest extends DeathRecipient { + BatchedScanSettings settings; + int uid; + + BatchedScanRequest(BatchedScanSettings settings, IBinder binder, int uid) { + super(0, null, binder, null); + this.settings = settings; + this.uid = uid; + } + public void binderDied() { + stopBatchedScan(settings, mBinder); + } + public String toString() { + return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}"; + } + } + + private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>(); + + public boolean isBatchedScanSupported() { + return mBatchedScanSupported; + } + + public void pollBatchedScan() { + enforceChangePermission(); + if (mBatchedScanSupported == false) return; + mWifiStateMachine.requestBatchedScanPoll(); + } + + /** + * see {@link android.net.wifi.WifiManager#requestBatchedScan()} + */ + public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder) { + enforceChangePermission(); + if (mBatchedScanSupported == false) return false; + requested = new BatchedScanSettings(requested); + if (requested.isInvalid()) return false; + BatchedScanRequest r = new BatchedScanRequest(requested, binder, Binder.getCallingUid()); + synchronized(mBatchedScanners) { + mBatchedScanners.add(r); + resolveBatchedScannersLocked(); + } + return true; + } + + public List<BatchedScanResult> getBatchedScanResults(String callingPackage) { + enforceAccessPermission(); + if (mBatchedScanSupported == false) return new ArrayList<BatchedScanResult>(); + int userId = UserHandle.getCallingUserId(); + int uid = Binder.getCallingUid(); + long ident = Binder.clearCallingIdentity(); + try { + if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) + != AppOpsManager.MODE_ALLOWED) { + return new ArrayList<BatchedScanResult>(); + } + int currentUser = ActivityManager.getCurrentUser(); + if (userId != currentUser) { + return new ArrayList<BatchedScanResult>(); + } else { + return mWifiStateMachine.syncGetBatchedScanResultsList(); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + + public void stopBatchedScan(BatchedScanSettings settings, IBinder binder) { + enforceChangePermission(); + if (mBatchedScanSupported == false) return; + synchronized(mBatchedScanners) { + BatchedScanRequest found = null; + for (BatchedScanRequest r : mBatchedScanners) { + if (r.mBinder.equals(binder) && r.settings.equals(settings)) { + found = r; + break; + } + } + if (found != null) { + mBatchedScanners.remove(found); + resolveBatchedScannersLocked(); + } + } + } + + private void resolveBatchedScannersLocked() { + BatchedScanSettings setting = new BatchedScanSettings(); + setting.scanIntervalSec = BatchedScanSettings.DEFAULT_INTERVAL_SEC; + int responsibleUid = 0; + setting.channelSet = new ArrayList<String>(); + + if (mBatchedScanners.size() == 0) { + mWifiStateMachine.setBatchedScanSettings(null, 0); + return; + } + + for (BatchedScanRequest r : mBatchedScanners) { + BatchedScanSettings s = r.settings; + if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED && + s.maxScansPerBatch < setting.maxScansPerBatch) { + setting.maxScansPerBatch = s.maxScansPerBatch; + responsibleUid = r.uid; + } + if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED && + s.maxApPerScan > setting.maxApPerScan) { + setting.maxApPerScan = s.maxApPerScan; + } + if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED && + s.scanIntervalSec < setting.scanIntervalSec) { + setting.scanIntervalSec = s.scanIntervalSec; + responsibleUid = r.uid; + } + if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED && + s.maxApForDistance > setting.maxApForDistance) { + setting.maxApForDistance = s.maxApForDistance; + } + if (s.channelSet != null) { + for (String i : s.channelSet) { + if (setting.channelSet.contains(i) == false) setting.channelSet.add(i); + } + } + } + if (setting.channelSet.size() == 0) setting.channelSet = null; + if (setting.scanIntervalSec < BatchedScanSettings.MIN_INTERVAL_SEC) { + setting.scanIntervalSec = BatchedScanSettings.MIN_INTERVAL_SEC; + } + if (setting.maxScansPerBatch == BatchedScanSettings.UNSPECIFIED) { + setting.maxScansPerBatch = BatchedScanSettings.DEFAULT_SCANS_PER_BATCH; + } + if (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED) { + setting.maxApPerScan = BatchedScanSettings.DEFAULT_AP_PER_SCAN; + } + if (setting.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) { + setting.scanIntervalSec = BatchedScanSettings.DEFAULT_INTERVAL_SEC; + } + if (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED) { + setting.maxApForDistance = BatchedScanSettings.DEFAULT_AP_FOR_DISTANCE; + } + mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid); + } + private void enforceAccessPermission() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, "WifiService"); @@ -569,11 +719,11 @@ public final class WifiService extends IWifiManager.Stub { int userId = UserHandle.getCallingUserId(); int uid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); - if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { - return new ArrayList<ScanResult>(); - } try { + if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) + != AppOpsManager.MODE_ALLOWED) { + return new ArrayList<ScanResult>(); + } int currentUser = ActivityManager.getCurrentUser(); if (userId != currentUser) { return new ArrayList<ScanResult>(); diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp index 48b86db..c871828 100644 --- a/services/jni/com_android_server_location_FlpHardwareProvider.cpp +++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp @@ -261,6 +261,75 @@ static void TranslateFromObject( } /* + * Helper function to unwrap Geofence structures from the Java Runtime calls. + */ +static void TranslateGeofenceFromGeofenceHardwareRequestParcelable( + JNIEnv* env, + jobject geofenceRequestObject, + Geofence& geofence) { + jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject); + + jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I"); + geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId); + + jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I"); + // this works because GeofenceHardwareRequest.java and fused_location.h have + // the same notion of geofence types + GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType); + if(type != TYPE_CIRCLE) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + geofence.data->type = type; + GeofenceCircle& circle = geofence.data->geofence.circle; + + jmethodID getLatitude = env->GetMethodID( + geofenceRequestClass, + "getLatitude", + "()D"); + circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude); + + jmethodID getLongitude = env->GetMethodID( + geofenceRequestClass, + "getLongitude", + "()D"); + circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude); + + jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D"); + circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius); + + GeofenceOptions* options = geofence.options; + jmethodID getMonitorTransitions = env->GetMethodID( + geofenceRequestClass, + "getMonitorTransitions", + "()I"); + options->monitor_transitions = env->CallIntMethod( + geofenceRequestObject, + getMonitorTransitions); + + jmethodID getUnknownTimer = env->GetMethodID( + geofenceRequestClass, + "getUnknownTimer", + "()I"); + options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer); + + jmethodID getNotificationResponsiveness = env->GetMethodID( + geofenceRequestClass, + "getNotificationResponsiveness", + "()D"); + options->notification_responsivenes_ms = env->CallIntMethod( + geofenceRequestObject, + getNotificationResponsiveness); + + jmethodID getLastTransition = env->GetMethodID( + geofenceRequestClass, + "getLastTransition", + "()I"); + options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition); + + // TODO: set data.sources_to_use when available +} + +/* * Helper function to transform FlpLocation into a java object. */ static void TranslateToObject(const FlpLocation* location, jobject& locationObject) { @@ -559,7 +628,7 @@ static void Init(JNIEnv* env, jobject obj) { } err = module->methods->open( - module, + module, FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice); if(err != 0) { ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err); @@ -749,10 +818,9 @@ static jboolean IsGeofencingSupported() { static void AddGeofences( JNIEnv* env, jobject object, - jintArray geofenceIdsArray, - jobjectArray geofencesArray) { - if(geofencesArray == NULL) { - ALOGE("Invalid Geofences to add: %p", geofencesArray); + jobjectArray geofenceRequestsArray) { + if(geofenceRequestsArray == NULL) { + ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray); ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); } @@ -760,23 +828,32 @@ static void AddGeofences( ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); } - jint geofencesCount = env->GetArrayLength(geofenceIdsArray); - Geofence* geofences = new Geofence[geofencesCount]; + jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray); + if(geofenceRequestsCount == 0) { + return; + } + + Geofence* geofences = new Geofence[geofenceRequestsCount]; 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]; + for (int i = 0; i < geofenceRequestsCount; ++i) { + geofences[i].data = new GeofenceData(); + geofences[i].options = new GeofenceOptions(); + jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i); - // TODO: fill in the GeofenceData - - // TODO: fill in the GeofenceOptions + TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]); } - sFlpGeofencingInterface->add_geofences(geofencesCount, &geofences); - if (geofences != NULL) delete[] geofences; + sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences); + if (geofences != NULL) { + for(int i = 0; i < geofenceRequestsCount; ++i) { + delete geofences[i].data; + delete geofences[i].options; + } + delete[] geofences; + } } static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) { @@ -847,41 +924,41 @@ static JNINativeMethod sMethods[] = { {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)}, {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)}, {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)}, - {"nativeStartBatching", - "(ILandroid/location/FusedBatchOptions;)V", + {"nativeStartBatching", + "(ILandroid/location/FusedBatchOptions;)V", reinterpret_cast<void*>(StartBatching)}, - {"nativeUpdateBatchingOptions", - "(ILandroid/location/FusedBatchOptions;)V", + {"nativeUpdateBatchingOptions", + "(ILandroid/location/FusedBatchOptions;)V", reinterpret_cast<void*>(UpdateBatchingOptions)}, {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)}, - {"nativeRequestBatchedLocation", - "(I)V", + {"nativeRequestBatchedLocation", + "(I)V", reinterpret_cast<void*>(GetBatchedLocation)}, - {"nativeInjectLocation", - "(Landroid/location/Location;)V", + {"nativeInjectLocation", + "(Landroid/location/Location;)V", reinterpret_cast<void*>(InjectLocation)}, - {"nativeIsDiagnosticSupported", - "()Z", + {"nativeIsDiagnosticSupported", + "()Z", reinterpret_cast<void*>(IsDiagnosticSupported)}, - {"nativeInjectDiagnosticData", - "(Ljava/lang/String;)V", + {"nativeInjectDiagnosticData", + "(Ljava/lang/String;)V", reinterpret_cast<void*>(InjectDiagnosticData)}, - {"nativeIsDeviceContextSupported", - "()Z", + {"nativeIsDeviceContextSupported", + "()Z", reinterpret_cast<void*>(IsDeviceContextSupported)}, - {"nativeInjectDeviceContext", - "(I)V", + {"nativeInjectDeviceContext", + "(I)V", reinterpret_cast<void*>(InjectDeviceContext)}, - {"nativeIsGeofencingSupported", - "()Z", + {"nativeIsGeofencingSupported", + "()Z", reinterpret_cast<void*>(IsGeofencingSupported)}, - {"nativeAddGeofences", - "([I[Landroid/location/Geofence;)V", + {"nativeAddGeofences", + "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V", reinterpret_cast<void*>(AddGeofences)}, {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)}, {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)}, - {"nativeModifyGeofenceOption", - "(IIIIII)V", + {"nativeModifyGeofenceOption", + "(IIIIII)V", reinterpret_cast<void*>(ModifyGeofenceOption)}, {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)} }; diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java index dff6661..e44652f 100644 --- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java +++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java @@ -67,7 +67,7 @@ public class SyncStorageEngineTest extends AndroidTestCase { /** * Test that we handle the case of a history row being old enough to purge before the - * correcponding sync is finished. This can happen if the clock changes while we are syncing. + * corresponding sync is finished. This can happen if the clock changes while we are syncing. * */ // TODO: this test causes AidlTest to fail. Omit for now @@ -104,6 +104,17 @@ public class SyncStorageEngineTest extends AndroidTestCase { engine.clearAndReadState(); assert(engine.getPendingOperationCount() == 1); + List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations(); + SyncStorageEngine.PendingOperation popRetrieved = pops.get(0); + assertEquals(pop.account, popRetrieved.account); + assertEquals(pop.reason, popRetrieved.reason); + assertEquals(pop.userId, popRetrieved.userId); + assertEquals(pop.syncSource, popRetrieved.syncSource); + assertEquals(pop.authority, popRetrieved.authority); + assertEquals(pop.expedited, popRetrieved.expedited); + assertEquals(pop.serviceName, popRetrieved.serviceName); + assert(android.content.PeriodicSync.syncExtrasEquals(pop.extras, popRetrieved.extras)); + } /** |