LocationManagerService now keeps track of the current user ID and denies location requests made by all but the foreground user. Additionally, location settings are now user-specific, rather than global to the device. Location provider services now run as specific users, and when the device's foreground user changes, we rebind to appropriately-owned providers. Bug: 6926385 Bug: 7247203 Change-Id: I346074959e96e52bcc77eeb188dffe322b690879
294 lines
9.2 KiB
Java
294 lines
9.2 KiB
Java
/*
|
|
* Copyright (C) 2009 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.server.location;
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.io.PrintWriter;
|
|
import java.util.List;
|
|
|
|
import android.content.Context;
|
|
import android.location.LocationProvider;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.RemoteException;
|
|
import android.os.UserHandle;
|
|
import android.os.WorkSource;
|
|
import android.util.Log;
|
|
|
|
import com.android.internal.location.ProviderProperties;
|
|
import com.android.internal.location.ILocationProvider;
|
|
import com.android.internal.location.ProviderRequest;
|
|
import com.android.server.LocationManagerService;
|
|
import com.android.server.ServiceWatcher;
|
|
|
|
/**
|
|
* Proxy for ILocationProvider implementations.
|
|
*/
|
|
public class LocationProviderProxy implements LocationProviderInterface {
|
|
private static final String TAG = "LocationProviderProxy";
|
|
private static final boolean D = LocationManagerService.D;
|
|
|
|
private final Context mContext;
|
|
private final String mName;
|
|
private final ServiceWatcher mServiceWatcher;
|
|
|
|
private Object mLock = new Object();
|
|
|
|
// cached values set by the location manager, synchronized on mLock
|
|
private ProviderProperties mProperties;
|
|
private boolean mEnabled = false;
|
|
private ProviderRequest mRequest = null;
|
|
private WorkSource mWorksource = new WorkSource();
|
|
|
|
public static LocationProviderProxy createAndBind(Context context, String name, String action,
|
|
List<String> initialPackageNames, Handler handler, int userId) {
|
|
LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
|
|
initialPackageNames, handler, userId);
|
|
if (proxy.bind()) {
|
|
return proxy;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private LocationProviderProxy(Context context, String name, String action,
|
|
List<String> initialPackageNames, Handler handler, int userId) {
|
|
mContext = context;
|
|
mName = name;
|
|
mServiceWatcher = new ServiceWatcher(mContext, TAG, action, initialPackageNames,
|
|
mNewServiceWork, handler, userId);
|
|
}
|
|
|
|
private boolean bind () {
|
|
return mServiceWatcher.start();
|
|
}
|
|
|
|
private ILocationProvider getService() {
|
|
return ILocationProvider.Stub.asInterface(mServiceWatcher.getBinder());
|
|
}
|
|
|
|
public String getConnectedPackageName() {
|
|
return mServiceWatcher.getBestPackageName();
|
|
}
|
|
|
|
/**
|
|
* Work to apply current state to a newly connected provider.
|
|
* Remember we can switch the service that implements a providers
|
|
* at run-time, so need to apply current state.
|
|
*/
|
|
private Runnable mNewServiceWork = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (D) Log.d(TAG, "applying state to connected service");
|
|
|
|
boolean enabled;
|
|
ProviderProperties properties = null;
|
|
ProviderRequest request;
|
|
WorkSource source;
|
|
ILocationProvider service;
|
|
synchronized (mLock) {
|
|
enabled = mEnabled;
|
|
request = mRequest;
|
|
source = mWorksource;
|
|
service = getService();
|
|
}
|
|
|
|
if (service == null) return;
|
|
|
|
try {
|
|
// load properties from provider
|
|
properties = service.getProperties();
|
|
if (properties == null) {
|
|
Log.e(TAG, mServiceWatcher.getBestPackageName() +
|
|
" has invalid locatino provider properties");
|
|
}
|
|
|
|
// apply current state to new service
|
|
if (enabled) {
|
|
service.enable();
|
|
if (request != null) {
|
|
service.setRequest(request, source);
|
|
}
|
|
}
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, e);
|
|
} catch (Exception e) {
|
|
// never let remote service crash system server
|
|
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
|
}
|
|
|
|
synchronized (mLock) {
|
|
mProperties = properties;
|
|
}
|
|
}
|
|
};
|
|
|
|
@Override
|
|
public String getName() {
|
|
return mName;
|
|
}
|
|
|
|
@Override
|
|
public ProviderProperties getProperties() {
|
|
synchronized (mLock) {
|
|
return mProperties;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void enable() {
|
|
synchronized (mLock) {
|
|
mEnabled = true;
|
|
}
|
|
ILocationProvider service = getService();
|
|
if (service == null) return;
|
|
|
|
try {
|
|
service.enable();
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, e);
|
|
} catch (Exception e) {
|
|
// never let remote service crash system server
|
|
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void disable() {
|
|
synchronized (mLock) {
|
|
mEnabled = false;
|
|
}
|
|
ILocationProvider service = getService();
|
|
if (service == null) return;
|
|
|
|
try {
|
|
service.disable();
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, e);
|
|
} catch (Exception e) {
|
|
// never let remote service crash system server
|
|
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isEnabled() {
|
|
synchronized (mLock) {
|
|
return mEnabled;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setRequest(ProviderRequest request, WorkSource source) {
|
|
synchronized (mLock) {
|
|
mRequest = request;
|
|
mWorksource = source;
|
|
}
|
|
ILocationProvider service = getService();
|
|
if (service == null) return;
|
|
|
|
try {
|
|
service.setRequest(request, source);
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, e);
|
|
} catch (Exception e) {
|
|
// never let remote service crash system server
|
|
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void switchUser(int userId) {
|
|
mServiceWatcher.switchUser(userId);
|
|
}
|
|
|
|
@Override
|
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
|
pw.append("REMOTE SERVICE");
|
|
pw.append(" name=").append(mName);
|
|
pw.append(" pkg=").append(mServiceWatcher.getBestPackageName());
|
|
pw.append(" version=").append("" + mServiceWatcher.getBestVersion());
|
|
pw.append('\n');
|
|
|
|
ILocationProvider service = getService();
|
|
if (service == null) {
|
|
pw.println("service down (null)");
|
|
return;
|
|
}
|
|
pw.flush();
|
|
|
|
try {
|
|
service.asBinder().dump(fd, args);
|
|
} catch (RemoteException e) {
|
|
pw.println("service down (RemoteException)");
|
|
Log.w(TAG, e);
|
|
} catch (Exception e) {
|
|
pw.println("service down (Exception)");
|
|
// never let remote service crash system server
|
|
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getStatus(Bundle extras) {
|
|
ILocationProvider service = getService();
|
|
if (service == null) return LocationProvider.TEMPORARILY_UNAVAILABLE;
|
|
|
|
try {
|
|
return service.getStatus(extras);
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, e);
|
|
} catch (Exception e) {
|
|
// never let remote service crash system server
|
|
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
|
}
|
|
return LocationProvider.TEMPORARILY_UNAVAILABLE;
|
|
}
|
|
|
|
@Override
|
|
public long getStatusUpdateTime() {
|
|
ILocationProvider service = getService();
|
|
if (service == null) return 0;
|
|
|
|
try {
|
|
return service.getStatusUpdateTime();
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, e);
|
|
} catch (Exception e) {
|
|
// never let remote service crash system server
|
|
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public boolean sendExtraCommand(String command, Bundle extras) {
|
|
ILocationProvider service = getService();
|
|
if (service == null) return false;
|
|
|
|
try {
|
|
return service.sendExtraCommand(command, extras);
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, e);
|
|
} catch (Exception e) {
|
|
// never let remote service crash system server
|
|
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
|
}
|
|
return false;
|
|
}
|
|
}
|