Home | History | Annotate | Download | only in location
      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.WorkSource;
     29 import android.util.Log;
     30 
     31 import com.android.internal.location.ProviderProperties;
     32 import com.android.internal.location.ILocationProvider;
     33 import com.android.internal.location.ProviderRequest;
     34 import com.android.server.LocationManagerService;
     35 import com.android.server.ServiceWatcher;
     36 
     37 /**
     38  * Proxy for ILocationProvider implementations.
     39  */
     40 public class LocationProviderProxy implements LocationProviderInterface {
     41     private static final String TAG = "LocationProviderProxy";
     42     private static final boolean D = LocationManagerService.D;
     43 
     44     private final Context mContext;
     45     private final String mName;
     46     private final ServiceWatcher mServiceWatcher;
     47 
     48     private Object mLock = new Object();
     49 
     50     // cached values set by the location manager, synchronized on mLock
     51     private ProviderProperties mProperties;
     52     private boolean mEnabled = false;
     53     private ProviderRequest mRequest = null;
     54     private WorkSource mWorksource = new WorkSource();
     55 
     56     public static LocationProviderProxy createAndBind(
     57             Context context, String name, String action,
     58             int overlaySwitchResId, int defaultServicePackageNameResId,
     59             int initialPackageNamesResId, Handler handler) {
     60         LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
     61                 overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId,
     62                 handler);
     63         if (proxy.bind()) {
     64             return proxy;
     65         } else {
     66             return null;
     67         }
     68     }
     69 
     70     private LocationProviderProxy(Context context, String name, String action,
     71             int overlaySwitchResId, int defaultServicePackageNameResId,
     72             int initialPackageNamesResId, Handler handler) {
     73         mContext = context;
     74         mName = name;
     75         mServiceWatcher = new ServiceWatcher(mContext, TAG + "-" + name, action, overlaySwitchResId,
     76                 defaultServicePackageNameResId, initialPackageNamesResId,
     77                 mNewServiceWork, handler);
     78     }
     79 
     80     private boolean bind () {
     81         return mServiceWatcher.start();
     82     }
     83 
     84     private ILocationProvider getService() {
     85         return ILocationProvider.Stub.asInterface(mServiceWatcher.getBinder());
     86     }
     87 
     88     public String getConnectedPackageName() {
     89         return mServiceWatcher.getBestPackageName();
     90     }
     91 
     92     /**
     93      * Work to apply current state to a newly connected provider.
     94      * Remember we can switch the service that implements a providers
     95      * at run-time, so need to apply current state.
     96      */
     97     private Runnable mNewServiceWork = new Runnable() {
     98         @Override
     99         public void run() {
    100             if (D) Log.d(TAG, "applying state to connected service");
    101 
    102             boolean enabled;
    103             ProviderProperties properties = null;
    104             ProviderRequest request;
    105             WorkSource source;
    106             ILocationProvider service;
    107             synchronized (mLock) {
    108                 enabled = mEnabled;
    109                 request = mRequest;
    110                 source = mWorksource;
    111                 service = getService();
    112             }
    113 
    114             if (service == null) return;
    115 
    116             try {
    117                 // load properties from provider
    118                 properties = service.getProperties();
    119                 if (properties == null) {
    120                     Log.e(TAG, mServiceWatcher.getBestPackageName() +
    121                             " has invalid locatino provider properties");
    122                 }
    123 
    124                 // apply current state to new service
    125                 if (enabled) {
    126                     service.enable();
    127                     if (request != null) {
    128                         service.setRequest(request, source);
    129                     }
    130                 }
    131             } catch (RemoteException e) {
    132                 Log.w(TAG, e);
    133             } catch (Exception e) {
    134                 // never let remote service crash system server
    135                 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
    136             }
    137 
    138             synchronized (mLock) {
    139                 mProperties = properties;
    140             }
    141         }
    142     };
    143 
    144     @Override
    145     public String getName() {
    146         return mName;
    147     }
    148 
    149     @Override
    150     public ProviderProperties getProperties() {
    151         synchronized (mLock) {
    152             return mProperties;
    153         }
    154     }
    155 
    156     @Override
    157     public void enable() {
    158         synchronized (mLock) {
    159             mEnabled = true;
    160         }
    161         ILocationProvider service = getService();
    162         if (service == null) return;
    163 
    164         try {
    165             service.enable();
    166         } catch (RemoteException e) {
    167             Log.w(TAG, e);
    168         } catch (Exception e) {
    169             // never let remote service crash system server
    170             Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
    171         }
    172     }
    173 
    174     @Override
    175     public void disable() {
    176         synchronized (mLock) {
    177             mEnabled = false;
    178         }
    179         ILocationProvider service = getService();
    180         if (service == null) return;
    181 
    182         try {
    183             service.disable();
    184         } catch (RemoteException e) {
    185             Log.w(TAG, e);
    186         } catch (Exception e) {
    187             // never let remote service crash system server
    188             Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
    189         }
    190     }
    191 
    192     @Override
    193     public boolean isEnabled() {
    194         synchronized (mLock) {
    195             return mEnabled;
    196         }
    197     }
    198 
    199     @Override
    200     public void setRequest(ProviderRequest request, WorkSource source) {
    201         synchronized (mLock) {
    202             mRequest = request;
    203             mWorksource = source;
    204         }
    205         ILocationProvider service = getService();
    206         if (service == null) return;
    207 
    208         try {
    209             service.setRequest(request, source);
    210         } catch (RemoteException e) {
    211             Log.w(TAG, e);
    212         } catch (Exception e) {
    213             // never let remote service crash system server
    214             Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
    215         }
    216     }
    217 
    218     @Override
    219     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    220         pw.append("REMOTE SERVICE");
    221         pw.append(" name=").append(mName);
    222         pw.append(" pkg=").append(mServiceWatcher.getBestPackageName());
    223         pw.append(" version=").append("" + mServiceWatcher.getBestVersion());
    224         pw.append('\n');
    225 
    226         ILocationProvider service = getService();
    227         if (service == null) {
    228             pw.println("service down (null)");
    229             return;
    230         }
    231         pw.flush();
    232 
    233         try {
    234             service.asBinder().dump(fd, args);
    235         } catch (RemoteException e) {
    236             pw.println("service down (RemoteException)");
    237             Log.w(TAG, e);
    238         } catch (Exception e) {
    239             pw.println("service down (Exception)");
    240             // never let remote service crash system server
    241             Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
    242         }
    243     }
    244 
    245     @Override
    246     public int getStatus(Bundle extras) {
    247         ILocationProvider service = getService();
    248         if (service == null) return LocationProvider.TEMPORARILY_UNAVAILABLE;
    249 
    250         try {
    251             return service.getStatus(extras);
    252         } catch (RemoteException e) {
    253             Log.w(TAG, e);
    254         } catch (Exception e) {
    255             // never let remote service crash system server
    256             Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
    257         }
    258         return LocationProvider.TEMPORARILY_UNAVAILABLE;
    259     }
    260 
    261     @Override
    262     public long getStatusUpdateTime() {
    263         ILocationProvider service = getService();
    264         if (service == null) return 0;
    265 
    266         try {
    267             return service.getStatusUpdateTime();
    268         } catch (RemoteException e) {
    269             Log.w(TAG, e);
    270         } catch (Exception e) {
    271             // never let remote service crash system server
    272             Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
    273         }
    274         return 0;
    275     }
    276 
    277     @Override
    278     public boolean sendExtraCommand(String command, Bundle extras) {
    279         ILocationProvider service = getService();
    280         if (service == null) return false;
    281 
    282         try {
    283             return service.sendExtraCommand(command, extras);
    284         } catch (RemoteException e) {
    285             Log.w(TAG, e);
    286         } catch (Exception e) {
    287             // never let remote service crash system server
    288             Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
    289         }
    290         return false;
    291     }
    292  }
    293