LocationProviderProxy.java revision 9158825f9c41869689d6b1786d7c7aa8bdd524ce
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
17package com.android.server.location;
18
19import java.io.FileDescriptor;
20import java.io.PrintWriter;
21import java.util.List;
22
23import android.content.Context;
24import android.location.LocationProvider;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.RemoteException;
28import android.os.WorkSource;
29import android.util.Log;
30
31import com.android.internal.location.ProviderProperties;
32import com.android.internal.location.ILocationProvider;
33import com.android.internal.location.ProviderRequest;
34import com.android.server.LocationManagerService;
35import com.android.server.ServiceWatcher;
36
37/**
38 * Proxy for ILocationProvider implementations.
39 */
40public 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