1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location; 18 19 import java.io.FileDescriptor; 20 import java.io.PrintWriter; 21 import java.util.List; 22 23 import android.content.Context; 24 import android.location.LocationProvider; 25 import android.os.Bundle; 26 import android.os.Handler; 27 import android.os.RemoteException; 28 import android.os.UserHandle; 29 import android.os.WorkSource; 30 import android.util.Log; 31 32 import com.android.internal.location.ProviderProperties; 33 import com.android.internal.location.ILocationProvider; 34 import com.android.internal.location.ProviderRequest; 35 import com.android.server.LocationManagerService; 36 import com.android.server.ServiceWatcher; 37 38 /** 39 * Proxy for ILocationProvider implementations. 40 */ 41 public class LocationProviderProxy implements LocationProviderInterface { 42 private static final String TAG = "LocationProviderProxy"; 43 private static final boolean D = LocationManagerService.D; 44 45 private final Context mContext; 46 private final String mName; 47 private final ServiceWatcher mServiceWatcher; 48 49 private Object mLock = new Object(); 50 51 // cached values set by the location manager, synchronized on mLock 52 private ProviderProperties mProperties; 53 private boolean mEnabled = false; 54 private ProviderRequest mRequest = null; 55 private WorkSource mWorksource = new WorkSource(); 56 createAndBind(Context context, String name, String action, List<String> initialPackageNames, Handler handler, int userId)57 public static LocationProviderProxy createAndBind(Context context, String name, String action, 58 List<String> initialPackageNames, Handler handler, int userId) { 59 LocationProviderProxy proxy = new LocationProviderProxy(context, name, action, 60 initialPackageNames, handler, userId); 61 if (proxy.bind()) { 62 return proxy; 63 } else { 64 return null; 65 } 66 } 67 LocationProviderProxy(Context context, String name, String action, List<String> initialPackageNames, Handler handler, int userId)68 private LocationProviderProxy(Context context, String name, String action, 69 List<String> initialPackageNames, Handler handler, int userId) { 70 mContext = context; 71 mName = name; 72 mServiceWatcher = new ServiceWatcher(mContext, TAG, action, initialPackageNames, 73 mNewServiceWork, handler, userId); 74 } 75 bind()76 private boolean bind () { 77 return mServiceWatcher.start(); 78 } 79 getService()80 private ILocationProvider getService() { 81 return ILocationProvider.Stub.asInterface(mServiceWatcher.getBinder()); 82 } 83 getConnectedPackageName()84 public String getConnectedPackageName() { 85 return mServiceWatcher.getBestPackageName(); 86 } 87 88 /** 89 * Work to apply current state to a newly connected provider. 90 * Remember we can switch the service that implements a providers 91 * at run-time, so need to apply current state. 92 */ 93 private Runnable mNewServiceWork = new Runnable() { 94 @Override 95 public void run() { 96 if (D) Log.d(TAG, "applying state to connected service"); 97 98 boolean enabled; 99 ProviderProperties properties = null; 100 ProviderRequest request; 101 WorkSource source; 102 ILocationProvider service; 103 synchronized (mLock) { 104 enabled = mEnabled; 105 request = mRequest; 106 source = mWorksource; 107 service = getService(); 108 } 109 110 if (service == null) return; 111 112 try { 113 // load properties from provider 114 properties = service.getProperties(); 115 if (properties == null) { 116 Log.e(TAG, mServiceWatcher.getBestPackageName() + 117 " has invalid locatino provider properties"); 118 } 119 120 // apply current state to new service 121 if (enabled) { 122 service.enable(); 123 if (request != null) { 124 service.setRequest(request, source); 125 } 126 } 127 } catch (RemoteException e) { 128 Log.w(TAG, e); 129 } catch (Exception e) { 130 // never let remote service crash system server 131 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 132 } 133 134 synchronized (mLock) { 135 mProperties = properties; 136 } 137 } 138 }; 139 140 @Override getName()141 public String getName() { 142 return mName; 143 } 144 145 @Override getProperties()146 public ProviderProperties getProperties() { 147 synchronized (mLock) { 148 return mProperties; 149 } 150 } 151 152 @Override enable()153 public void enable() { 154 synchronized (mLock) { 155 mEnabled = true; 156 } 157 ILocationProvider service = getService(); 158 if (service == null) return; 159 160 try { 161 service.enable(); 162 } catch (RemoteException e) { 163 Log.w(TAG, e); 164 } catch (Exception e) { 165 // never let remote service crash system server 166 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 167 } 168 } 169 170 @Override disable()171 public void disable() { 172 synchronized (mLock) { 173 mEnabled = false; 174 } 175 ILocationProvider service = getService(); 176 if (service == null) return; 177 178 try { 179 service.disable(); 180 } catch (RemoteException e) { 181 Log.w(TAG, e); 182 } catch (Exception e) { 183 // never let remote service crash system server 184 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 185 } 186 } 187 188 @Override isEnabled()189 public boolean isEnabled() { 190 synchronized (mLock) { 191 return mEnabled; 192 } 193 } 194 195 @Override setRequest(ProviderRequest request, WorkSource source)196 public void setRequest(ProviderRequest request, WorkSource source) { 197 synchronized (mLock) { 198 mRequest = request; 199 mWorksource = source; 200 } 201 ILocationProvider service = getService(); 202 if (service == null) return; 203 204 try { 205 service.setRequest(request, source); 206 } catch (RemoteException e) { 207 Log.w(TAG, e); 208 } catch (Exception e) { 209 // never let remote service crash system server 210 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 211 } 212 } 213 214 @Override switchUser(int userId)215 public void switchUser(int userId) { 216 mServiceWatcher.switchUser(userId); 217 } 218 219 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)220 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 221 pw.append("REMOTE SERVICE"); 222 pw.append(" name=").append(mName); 223 pw.append(" pkg=").append(mServiceWatcher.getBestPackageName()); 224 pw.append(" version=").append("" + mServiceWatcher.getBestVersion()); 225 pw.append('\n'); 226 227 ILocationProvider service = getService(); 228 if (service == null) { 229 pw.println("service down (null)"); 230 return; 231 } 232 pw.flush(); 233 234 try { 235 service.asBinder().dump(fd, args); 236 } catch (RemoteException e) { 237 pw.println("service down (RemoteException)"); 238 Log.w(TAG, e); 239 } catch (Exception e) { 240 pw.println("service down (Exception)"); 241 // never let remote service crash system server 242 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 243 } 244 } 245 246 @Override getStatus(Bundle extras)247 public int getStatus(Bundle extras) { 248 ILocationProvider service = getService(); 249 if (service == null) return LocationProvider.TEMPORARILY_UNAVAILABLE; 250 251 try { 252 return service.getStatus(extras); 253 } catch (RemoteException e) { 254 Log.w(TAG, e); 255 } catch (Exception e) { 256 // never let remote service crash system server 257 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 258 } 259 return LocationProvider.TEMPORARILY_UNAVAILABLE; 260 } 261 262 @Override getStatusUpdateTime()263 public long getStatusUpdateTime() { 264 ILocationProvider service = getService(); 265 if (service == null) return 0; 266 267 try { 268 return service.getStatusUpdateTime(); 269 } catch (RemoteException e) { 270 Log.w(TAG, e); 271 } catch (Exception e) { 272 // never let remote service crash system server 273 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 274 } 275 return 0; 276 } 277 278 @Override sendExtraCommand(String command, Bundle extras)279 public boolean sendExtraCommand(String command, Bundle extras) { 280 ILocationProvider service = getService(); 281 if (service == null) return false; 282 283 try { 284 return service.sendExtraCommand(command, extras); 285 } catch (RemoteException e) { 286 Log.w(TAG, e); 287 } catch (Exception e) { 288 // never let remote service crash system server 289 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 290 } 291 return false; 292 } 293 } 294