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