blob: ddf3afef17869746cd77152c6347f8a545b87d2a [file] [log] [blame]
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -08001/*
2 * Copyright (C) 2007 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;
18
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080019import android.app.AlarmManager;
20import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -080022import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080025import android.content.IntentFilter;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080026import android.content.pm.ActivityInfo;
27import android.content.pm.PackageManager;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080028import android.content.pm.PackageInfo;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080029import android.content.pm.ResolveInfo;
30import android.content.pm.PackageItemInfo;
31import android.content.res.TypedArray;
32import android.content.res.XmlResourceParser;
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -080033import android.gadget.GadgetManager;
The Android Open Source Projectda996f32009-02-13 12:57:50 -080034import android.gadget.GadgetProviderInfo;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080035import android.net.Uri;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080036import android.os.Binder;
The Android Open Source Projectda996f32009-02-13 12:57:50 -080037import android.os.Bundle;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080038import android.os.RemoteException;
39import android.os.SystemClock;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080040import android.util.AttributeSet;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080041import android.util.Config;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080042import android.util.Log;
43import android.util.Xml;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080044import android.widget.RemoteViews;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080045
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080046import java.io.IOException;
47import java.io.File;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080048import java.io.FileDescriptor;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080049import java.io.FileInputStream;
50import java.io.FileOutputStream;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080051import java.io.PrintWriter;
52import java.util.ArrayList;
53import java.util.List;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080054import java.util.HashMap;
55import java.util.HashSet;
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -080056
57import com.android.internal.gadget.IGadgetService;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080058import com.android.internal.gadget.IGadgetHost;
59import com.android.internal.util.XmlUtils;
60import com.android.internal.util.FastXmlSerializer;
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -080061
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080062import org.xmlpull.v1.XmlPullParser;
63import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080064import org.xmlpull.v1.XmlSerializer;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080065
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -080066class GadgetService extends IGadgetService.Stub
67{
68 private static final String TAG = "GadgetService";
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080069 private static final boolean LOGD = Config.LOGD || false;
70
71 private static final String SETTINGS_FILENAME = "gadgets.xml";
72 private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
73
74 /*
75 * When identifying a Host or Provider based on the calling process, use the uid field.
76 * When identifying a Host or Provider based on a package manager broadcast, use the
77 * package given.
78 */
79
80 static class Provider {
81 int uid;
The Android Open Source Projectda996f32009-02-13 12:57:50 -080082 GadgetProviderInfo info;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080083 ArrayList<GadgetId> instances = new ArrayList();
84 PendingIntent broadcast;
85
86 int tag; // for use while saving state (the index)
87 }
88
89 static class Host {
90 int uid;
91 int hostId;
92 String packageName;
93 ArrayList<GadgetId> instances = new ArrayList();
94 IGadgetHost callbacks;
95
96 int tag; // for use while saving state (the index)
97 }
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -080098
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -080099 static class GadgetId {
100 int gadgetId;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800101 Provider provider;
102 RemoteViews views;
103 Host host;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800104 }
105
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -0800106 Context mContext;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800107 PackageManager mPackageManager;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800108 AlarmManager mAlarmManager;
109 ArrayList<Provider> mInstalledProviders = new ArrayList();
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800110 int mNextGadgetId = GadgetManager.INVALID_GADGET_ID + 1;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800111 ArrayList<GadgetId> mGadgetIds = new ArrayList();
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800112 ArrayList<Host> mHosts = new ArrayList();
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -0800113
114 GadgetService(Context context) {
115 mContext = context;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800116 mPackageManager = context.getPackageManager();
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800117 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
118
119 getGadgetList();
120 loadStateLocked();
121
122 // Register for the boot completed broadcast, so we can send the
123 // ENABLE broacasts. If we try to send them now, they time out,
124 // because the system isn't ready to handle them yet.
125 mContext.registerReceiver(mBroadcastReceiver,
126 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
127
128 // Register for broadcasts about package install, etc., so we can
129 // update the provider list.
130 IntentFilter filter = new IntentFilter();
131 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800132 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
133 filter.addDataScheme("package");
134 mContext.registerReceiver(mBroadcastReceiver, filter);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800135 }
136
137 @Override
138 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800139 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800140 != PackageManager.PERMISSION_GRANTED) {
141 pw.println("Permission Denial: can't dump from from pid="
142 + Binder.getCallingPid()
143 + ", uid=" + Binder.getCallingUid());
144 return;
145 }
146
147 synchronized (mGadgetIds) {
148 int N = mInstalledProviders.size();
149 pw.println("Providers: (size=" + N + ")");
150 for (int i=0; i<N; i++) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800151 GadgetProviderInfo info = mInstalledProviders.get(i).info;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800152 pw.println(" [" + i + "] provder=" + info.provider
153 + " min=(" + info.minWidth + "x" + info.minHeight + ")"
154 + " updatePeriodMillis=" + info.updatePeriodMillis
155 + " initialLayout=" + info.initialLayout);
156 }
157
158 N = mGadgetIds.size();
159 pw.println("GadgetIds: (size=" + N + ")");
160 for (int i=0; i<N; i++) {
161 GadgetId id = mGadgetIds.get(i);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800162 pw.println(" [" + i + "] gadgetId=" + id.gadgetId
163 + " host=" + id.host.hostId + "/" + id.host.packageName + " provider="
164 + (id.provider == null ? "null" : id.provider.info.provider)
165 + " host.callbacks=" + (id.host != null ? id.host.callbacks : "(no host)")
166 + " views=" + id.views);
167 }
168
169 N = mHosts.size();
170 pw.println("Hosts: (size=" + N + ")");
171 for (int i=0; i<N; i++) {
172 Host host = mHosts.get(i);
173 pw.println(" [" + i + "] packageName=" + host.packageName + " uid=" + host.uid
174 + " hostId=" + host.hostId + " callbacks=" + host.callbacks
175 + " instances.size=" + host.instances.size());
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800176 }
177 }
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -0800178 }
179
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800180 public int allocateGadgetId(String packageName, int hostId) {
181 int callingUid = enforceCallingUid(packageName);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800182 synchronized (mGadgetIds) {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800183 int gadgetId = mNextGadgetId++;
184
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800185 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
186
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800187 GadgetId id = new GadgetId();
188 id.gadgetId = gadgetId;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800189 id.host = host;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800190
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800191 host.instances.add(id);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800192 mGadgetIds.add(id);
193
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800194 saveStateLocked();
195
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800196 return gadgetId;
197 }
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -0800198 }
199
200 public void deleteGadgetId(int gadgetId) {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800201 synchronized (mGadgetIds) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800202 int callingUid = getCallingUid();
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800203 final int N = mGadgetIds.size();
204 for (int i=0; i<N; i++) {
205 GadgetId id = mGadgetIds.get(i);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800206 if (id.provider != null && canAccessGadgetId(id, callingUid)) {
207 deleteGadgetLocked(id);
208
209 saveStateLocked();
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800210 return;
211 }
212 }
213 }
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -0800214 }
215
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800216 public void deleteHost(int hostId) {
217 synchronized (mGadgetIds) {
218 int callingUid = getCallingUid();
219 Host host = lookupHostLocked(callingUid, hostId);
220 if (host != null) {
221 deleteHostLocked(host);
222 saveStateLocked();
223 }
224 }
225 }
226
227 public void deleteAllHosts() {
228 synchronized (mGadgetIds) {
229 int callingUid = getCallingUid();
230 final int N = mHosts.size();
231 boolean changed = false;
232 for (int i=0; i<N; i++) {
233 Host host = mHosts.get(i);
234 if (host.uid == callingUid) {
235 deleteHostLocked(host);
236 changed = true;
237 }
238 }
239 if (changed) {
240 saveStateLocked();
241 }
242 }
243 }
244
245 void deleteHostLocked(Host host) {
246 final int N = host.instances.size();
247 for (int i=0; i<N; i++) {
248 GadgetId id = host.instances.get(i);
249 deleteGadgetLocked(id);
250 }
251 host.instances.clear();
252 mHosts.remove(host);
253 // it's gone or going away, abruptly drop the callback connection
254 host.callbacks = null;
255 }
256
257 void deleteGadgetLocked(GadgetId id) {
258 Host host = id.host;
259 host.instances.remove(id);
260 pruneHostLocked(host);
261
262 mGadgetIds.remove(id);
263
264 Provider p = id.provider;
265 if (p != null) {
266 p.instances.remove(id);
267 // send the broacast saying that this gadgetId has been deleted
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800268 Intent intent = new Intent(GadgetManager.ACTION_GADGET_DELETED);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800269 intent.setComponent(p.info.provider);
270 intent.putExtra(GadgetManager.EXTRA_GADGET_ID, id.gadgetId);
271 mContext.sendBroadcast(intent);
272 if (p.instances.size() == 0) {
273 // cancel the future updates
274 cancelBroadcasts(p);
275
276 // send the broacast saying that the provider is not in use any more
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800277 intent = new Intent(GadgetManager.ACTION_GADGET_DISABLED);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800278 intent.setComponent(p.info.provider);
279 mContext.sendBroadcast(intent);
280 }
281 }
282 }
283
284 void cancelBroadcasts(Provider p) {
285 if (p.broadcast != null) {
286 mAlarmManager.cancel(p.broadcast);
287 long token = Binder.clearCallingIdentity();
288 try {
289 p.broadcast.cancel();
290 } finally {
291 Binder.restoreCallingIdentity(token);
292 }
293 p.broadcast = null;
294 }
295 }
296
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -0800297 public void bindGadgetId(int gadgetId, ComponentName provider) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800298 mContext.enforceCallingPermission(android.Manifest.permission.BIND_GADGET,
299 "bindGagetId gadgetId=" + gadgetId + " provider=" + provider);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800300 synchronized (mGadgetIds) {
301 GadgetId id = lookupGadgetIdLocked(gadgetId);
302 if (id == null) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800303 throw new IllegalArgumentException("bad gadgetId");
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800304 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800305 if (id.provider != null) {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800306 throw new IllegalArgumentException("gadgetId " + gadgetId + " already bound to "
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800307 + id.provider.info.provider);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800308 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800309 Provider p = lookupProviderLocked(provider);
310 if (p == null) {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800311 throw new IllegalArgumentException("not a gadget provider: " + provider);
312 }
313
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800314 id.provider = p;
315 p.instances.add(id);
316 int instancesSize = p.instances.size();
317 if (instancesSize == 1) {
318 // tell the provider that it's ready
319 sendEnableIntentLocked(p);
320 }
321
322 // send an update now -- We need this update now, and just for this gadgetId.
323 // It's less critical when the next one happens, so when we schdule the next one,
324 // we add updatePeriodMillis to its start time. That time will have some slop,
325 // but that's okay.
326 sendUpdateIntentLocked(p, new int[] { gadgetId });
327
328 // schedule the future updates
329 registerForBroadcastsLocked(p, getGadgetIds(p));
330 saveStateLocked();
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800331 }
332 }
333
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800334 public GadgetProviderInfo getGadgetInfo(int gadgetId) {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800335 synchronized (mGadgetIds) {
336 GadgetId id = lookupGadgetIdLocked(gadgetId);
337 if (id != null) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800338 return id.provider.info;
339 }
340 return null;
341 }
342 }
343
344 public RemoteViews getGadgetViews(int gadgetId) {
345 synchronized (mGadgetIds) {
346 GadgetId id = lookupGadgetIdLocked(gadgetId);
347 if (id != null) {
348 return id.views;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800349 }
350 return null;
351 }
352 }
353
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800354 public List<GadgetProviderInfo> getInstalledProviders() {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800355 synchronized (mGadgetIds) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800356 final int N = mInstalledProviders.size();
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800357 ArrayList<GadgetProviderInfo> result = new ArrayList(N);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800358 for (int i=0; i<N; i++) {
359 result.add(mInstalledProviders.get(i).info);
360 }
361 return result;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800362 }
363 }
364
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800365 public void updateGadgetIds(int[] gadgetIds, RemoteViews views) {
366 if (gadgetIds == null) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800367 return;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800368 }
369 if (gadgetIds.length == 0) {
370 return;
371 }
372 final int N = gadgetIds.length;
373
374 synchronized (mGadgetIds) {
375 for (int i=0; i<N; i++) {
376 GadgetId id = lookupGadgetIdLocked(gadgetIds[i]);
377 updateGadgetInstanceLocked(id, views);
378 }
379 }
380 }
381
382 public void updateGadgetProvider(ComponentName provider, RemoteViews views) {
383 synchronized (mGadgetIds) {
384 Provider p = lookupProviderLocked(provider);
385 if (p == null) {
386 Log.w(TAG, "updateGadget: provider doesn't exist: " + provider);
387 return;
388 }
389 ArrayList<GadgetId> instances = p.instances;
390 final int N = instances.size();
391 for (int i=0; i<N; i++) {
392 GadgetId id = instances.get(i);
393 updateGadgetInstanceLocked(id, views);
394 }
395 }
396 }
397
398 void updateGadgetInstanceLocked(GadgetId id, RemoteViews views) {
399 // allow for stale gadgetIds and other badness
400 // lookup also checks that the calling process can access the gadget id
401 // drop unbound gadget ids (shouldn't be possible under normal circumstances)
402 if (id != null && id.provider != null) {
403 id.views = views;
404
405 // is anyone listening?
406 if (id.host.callbacks != null) {
407 try {
408 // the lock is held, but this is a oneway call
409 id.host.callbacks.updateGadget(id.gadgetId, views);
410 } catch (RemoteException e) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800411 // It failed; remove the callback. No need to prune because
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800412 // we know that this host is still referenced by this instance.
413 id.host.callbacks = null;
414 }
415 }
416 }
417 }
418
419 public int[] startListening(IGadgetHost callbacks, String packageName, int hostId,
420 List<RemoteViews> updatedViews) {
421 int callingUid = enforceCallingUid(packageName);
422 synchronized (mGadgetIds) {
423 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
424 host.callbacks = callbacks;
425
426 updatedViews.clear();
427
428 ArrayList<GadgetId> instances = host.instances;
429 int N = instances.size();
430 int[] updatedIds = new int[N];
431 for (int i=0; i<N; i++) {
432 GadgetId id = instances.get(i);
433 updatedIds[i] = id.gadgetId;
434 updatedViews.add(id.views);
435 }
436 return updatedIds;
437 }
438 }
439
440 public void stopListening(int hostId) {
441 synchronized (mGadgetIds) {
442 Host host = lookupHostLocked(getCallingUid(), hostId);
443 host.callbacks = null;
444 pruneHostLocked(host);
445 }
446 }
447
448 boolean canAccessGadgetId(GadgetId id, int callingUid) {
449 if (id.host.uid == callingUid) {
450 // Apps hosting the gadget have access to it.
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800451 return true;
452 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800453 if (id.provider != null && id.provider.uid == callingUid) {
454 // Apps providing the gadget have access to it (if the gadgetId has been bound)
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800455 return true;
456 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800457 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_GADGET)
458 == PackageManager.PERMISSION_GRANTED) {
459 // Apps that can bind have access to all gadgetIds.
460 return true;
461 }
462 // Nobody else can access it.
463 // TODO: convert callingPackage over to use UID-based checking instead
464 // TODO: our temp solution is to short-circuit this security check
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800465 return true;
466 }
467
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800468 GadgetId lookupGadgetIdLocked(int gadgetId) {
469 int callingUid = getCallingUid();
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800470 final int N = mGadgetIds.size();
471 for (int i=0; i<N; i++) {
472 GadgetId id = mGadgetIds.get(i);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800473 if (id.gadgetId == gadgetId && canAccessGadgetId(id, callingUid)) {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800474 return id;
475 }
476 }
477 return null;
478 }
479
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800480 Provider lookupProviderLocked(ComponentName provider) {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800481 final int N = mInstalledProviders.size();
482 for (int i=0; i<N; i++) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800483 Provider p = mInstalledProviders.get(i);
484 if (p.info.provider.equals(provider)) {
485 return p;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800486 }
487 }
488 return null;
489 }
490
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800491 Host lookupHostLocked(int uid, int hostId) {
492 final int N = mHosts.size();
493 for (int i=0; i<N; i++) {
494 Host h = mHosts.get(i);
495 if (h.uid == uid && h.hostId == hostId) {
496 return h;
497 }
498 }
499 return null;
500 }
501
502 Host lookupOrAddHostLocked(int uid, String packageName, int hostId) {
503 final int N = mHosts.size();
504 for (int i=0; i<N; i++) {
505 Host h = mHosts.get(i);
506 if (h.hostId == hostId && h.packageName.equals(packageName)) {
507 return h;
508 }
509 }
510 Host host = new Host();
511 host.packageName = packageName;
512 host.uid = uid;
513 host.hostId = hostId;
514 mHosts.add(host);
515 return host;
516 }
517
518 void pruneHostLocked(Host host) {
519 if (host.instances.size() == 0 && host.callbacks == null) {
520 mHosts.remove(host);
521 }
522 }
523
524 void getGadgetList() {
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800525 PackageManager pm = mPackageManager;
526
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800527 Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800528 List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
529 PackageManager.GET_META_DATA);
530
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800531 final int N = broadcastReceivers.size();
532 for (int i=0; i<N; i++) {
533 ResolveInfo ri = broadcastReceivers.get(i);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800534 addProviderLocked(ri);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800535 }
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800536 }
537
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800538 boolean addProviderLocked(ResolveInfo ri) {
539 Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800540 ri.activityInfo.name), ri);
541 if (p != null) {
542 mInstalledProviders.add(p);
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800543 return true;
544 } else {
545 return false;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800546 }
547 }
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800548
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800549 void removeProviderLocked(int index, Provider p) {
550 int N = p.instances.size();
551 for (int i=0; i<N; i++) {
552 GadgetId id = p.instances.get(i);
553 // Call back with empty RemoteViews
554 updateGadgetInstanceLocked(id, null);
555 // Stop telling the host about updates for this from now on
556 cancelBroadcasts(p);
557 // clear out references to this gadgetID
558 id.host.instances.remove(id);
559 mGadgetIds.remove(id);
560 id.provider = null;
561 pruneHostLocked(id.host);
562 id.host = null;
563 }
564 p.instances.clear();
565 mInstalledProviders.remove(index);
566 // no need to send the DISABLE broadcast, since the receiver is gone anyway
567 cancelBroadcasts(p);
568 }
569
570 void sendEnableIntentLocked(Provider p) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800571 Intent intent = new Intent(GadgetManager.ACTION_GADGET_ENABLED);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800572 intent.setComponent(p.info.provider);
573 mContext.sendBroadcast(intent);
574 }
575
576 void sendUpdateIntentLocked(Provider p, int[] gadgetIds) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800577 if (gadgetIds != null && gadgetIds.length > 0) {
578 Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
579 intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds);
580 intent.setComponent(p.info.provider);
581 mContext.sendBroadcast(intent);
582 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800583 }
584
585 void registerForBroadcastsLocked(Provider p, int[] gadgetIds) {
586 if (p.info.updatePeriodMillis > 0) {
587 // if this is the first instance, set the alarm. otherwise,
588 // rely on the fact that we've already set it and that
589 // PendingIntent.getBroadcast will update the extras.
590 boolean alreadyRegistered = p.broadcast != null;
591 int instancesSize = p.instances.size();
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800592 Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800593 intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds);
594 intent.setComponent(p.info.provider);
595 long token = Binder.clearCallingIdentity();
596 try {
597 p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
598 PendingIntent.FLAG_UPDATE_CURRENT);
599 } finally {
600 Binder.restoreCallingIdentity(token);
601 }
602 if (!alreadyRegistered) {
603 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
604 SystemClock.elapsedRealtime() + p.info.updatePeriodMillis,
605 p.info.updatePeriodMillis, p.broadcast);
606 }
607 }
608 }
609
610 static int[] getGadgetIds(Provider p) {
611 int instancesSize = p.instances.size();
612 int gadgetIds[] = new int[instancesSize];
613 for (int i=0; i<instancesSize; i++) {
614 gadgetIds[i] = p.instances.get(i).gadgetId;
615 }
616 return gadgetIds;
617 }
618
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800619 private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800620 Provider p = null;
621
622 ActivityInfo activityInfo = ri.activityInfo;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800623 XmlResourceParser parser = null;
624 try {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800625 parser = activityInfo.loadXmlMetaData(mPackageManager,
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800626 GadgetManager.META_DATA_GADGET_PROVIDER);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800627 if (parser == null) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800628 Log.w(TAG, "No " + GadgetManager.META_DATA_GADGET_PROVIDER + " meta-data for "
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800629 + "gadget provider '" + component + '\'');
630 return null;
631 }
632
633 AttributeSet attrs = Xml.asAttributeSet(parser);
634
635 int type;
636 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
637 && type != XmlPullParser.START_TAG) {
638 // drain whitespace, comments, etc.
639 }
640
641 String nodeName = parser.getName();
642 if (!"gadget-provider".equals(nodeName)) {
643 Log.w(TAG, "Meta-data does not start with gadget-provider tag for"
644 + " gadget provider '" + component + '\'');
645 return null;
646 }
647
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800648 p = new Provider();
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800649 GadgetProviderInfo info = p.info = new GadgetProviderInfo();
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800650
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800651 info.provider = component;
652 p.uid = activityInfo.applicationInfo.uid;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800653
654 TypedArray sa = mContext.getResources().obtainAttributes(attrs,
655 com.android.internal.R.styleable.GadgetProviderInfo);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800656 info.minWidth = sa.getDimensionPixelSize(
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800657 com.android.internal.R.styleable.GadgetProviderInfo_minWidth, 0);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800658 info.minHeight = sa.getDimensionPixelSize(
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800659 com.android.internal.R.styleable.GadgetProviderInfo_minHeight, 0);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800660 info.updatePeriodMillis = sa.getInt(
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800661 com.android.internal.R.styleable.GadgetProviderInfo_updatePeriodMillis, 0);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800662 info.initialLayout = sa.getResourceId(
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800663 com.android.internal.R.styleable.GadgetProviderInfo_initialLayout, 0);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800664 String className = sa.getString(
665 com.android.internal.R.styleable.GadgetProviderInfo_configure);
666 if (className != null) {
667 info.configure = new ComponentName(component.getPackageName(), className);
668 }
669 info.label = activityInfo.loadLabel(mPackageManager).toString();
670 info.icon = ri.getIconResource();
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800671 sa.recycle();
672 } catch (Exception e) {
673 // Ok to catch Exception here, because anything going wrong because
674 // of what a client process passes to us should not be fatal for the
675 // system process.
676 Log.w(TAG, "XML parsing failed for gadget provider '" + component + '\'', e);
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800677 return null;
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800678 } finally {
679 if (parser != null) parser.close();
680 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800681 return p;
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -0800682 }
683
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800684 int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
685 PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
686 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
687 throw new PackageManager.NameNotFoundException();
688 }
689 return pkgInfo.applicationInfo.uid;
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -0800690 }
691
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800692 int enforceCallingUid(String packageName) throws IllegalArgumentException {
693 int callingUid = getCallingUid();
694 int packageUid;
695 try {
696 packageUid = getUidForPackage(packageName);
697 } catch (PackageManager.NameNotFoundException ex) {
698 throw new IllegalArgumentException("packageName and uid don't match packageName="
699 + packageName);
700 }
701 if (callingUid != packageUid) {
702 throw new IllegalArgumentException("packageName and uid don't match packageName="
703 + packageName);
704 }
705 return callingUid;
706 }
707
708 void sendInitialBroadcasts() {
709 synchronized (mGadgetIds) {
710 final int N = mInstalledProviders.size();
711 for (int i=0; i<N; i++) {
712 Provider p = mInstalledProviders.get(i);
713 if (p.instances.size() > 0) {
714 sendEnableIntentLocked(p);
715 int[] gadgetIds = getGadgetIds(p);
716 sendUpdateIntentLocked(p, gadgetIds);
717 registerForBroadcastsLocked(p, gadgetIds);
718 }
719 }
720 }
721 }
722
723 // only call from initialization -- it assumes that the data structures are all empty
724 void loadStateLocked() {
725 File temp = savedStateTempFile();
726 File real = savedStateRealFile();
727
728 // prefer the real file. If it doesn't exist, use the temp one, and then copy it to the
729 // real one. if there is both a real file and a temp one, assume that the temp one isn't
730 // fully written and delete it.
731 if (real.exists()) {
732 readStateFromFileLocked(real);
733 if (temp.exists()) {
734 temp.delete();
735 }
736 } else if (temp.exists()) {
737 readStateFromFileLocked(temp);
738 temp.renameTo(real);
739 }
740 }
741
742 void saveStateLocked() {
743 File temp = savedStateTempFile();
744 File real = savedStateRealFile();
745
746 if (!real.exists()) {
747 // If the real one doesn't exist, it's either because this is the first time
748 // or because something went wrong while copying them. In this case, we can't
749 // trust anything that's in temp. In order to have the loadState code not
750 // use the temporary one until it's fully written, create an empty file
751 // for real, which will we'll shortly delete.
752 try {
753 real.createNewFile();
754 } catch (IOException e) {
755 }
756 }
757
758 if (temp.exists()) {
759 temp.delete();
760 }
761
762 writeStateToFileLocked(temp);
763
764 real.delete();
765 temp.renameTo(real);
766 }
767
768 void writeStateToFileLocked(File file) {
769 FileOutputStream stream = null;
770 int N;
771
772 try {
773 stream = new FileOutputStream(file, false);
774 XmlSerializer out = new FastXmlSerializer();
775 out.setOutput(stream, "utf-8");
776 out.startDocument(null, true);
777
778
779 out.startTag(null, "gs");
780
781 int providerIndex = 0;
782 N = mInstalledProviders.size();
783 for (int i=0; i<N; i++) {
784 Provider p = mInstalledProviders.get(i);
785 if (p.instances.size() > 0) {
786 out.startTag(null, "p");
787 out.attribute(null, "pkg", p.info.provider.getPackageName());
788 out.attribute(null, "cl", p.info.provider.getClassName());
789 out.endTag(null, "h");
790 p.tag = providerIndex;
791 providerIndex++;
792 }
793 }
794
795 N = mHosts.size();
796 for (int i=0; i<N; i++) {
797 Host host = mHosts.get(i);
798 out.startTag(null, "h");
799 out.attribute(null, "pkg", host.packageName);
800 out.attribute(null, "id", Integer.toHexString(host.hostId));
801 out.endTag(null, "h");
802 host.tag = i;
803 }
804
805 N = mGadgetIds.size();
806 for (int i=0; i<N; i++) {
807 GadgetId id = mGadgetIds.get(i);
808 out.startTag(null, "g");
809 out.attribute(null, "id", Integer.toHexString(id.gadgetId));
810 out.attribute(null, "h", Integer.toHexString(id.host.tag));
811 if (id.provider != null) {
812 out.attribute(null, "p", Integer.toHexString(id.provider.tag));
813 }
814 out.endTag(null, "g");
815 }
816
817 out.endTag(null, "gs");
818
819 out.endDocument();
820 stream.close();
821 } catch (IOException e) {
822 try {
823 if (stream != null) {
824 stream.close();
825 }
826 } catch (IOException ex) {
827 }
828 if (file.exists()) {
829 file.delete();
830 }
831 }
832 }
833
834 void readStateFromFileLocked(File file) {
835 FileInputStream stream = null;
836
837 boolean success = false;
838
839 try {
840 stream = new FileInputStream(file);
841 XmlPullParser parser = Xml.newPullParser();
842 parser.setInput(stream, null);
843
844 int type;
845 int providerIndex = 0;
846 HashMap<Integer,Provider> loadedProviders = new HashMap();
847 do {
848 type = parser.next();
849 if (type == XmlPullParser.START_TAG) {
850 String tag = parser.getName();
851 if ("p".equals(tag)) {
852 // TODO: do we need to check that this package has the same signature
853 // as before?
854 String pkg = parser.getAttributeValue(null, "pkg");
855 String cl = parser.getAttributeValue(null, "cl");
856 Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
857 // if it wasn't uninstalled or something
858 if (p != null) {
859 loadedProviders.put(providerIndex, p);
860 }
861 providerIndex++;
862 }
863 else if ("h".equals(tag)) {
864 Host host = new Host();
865
866 // TODO: do we need to check that this package has the same signature
867 // as before?
868 host.packageName = parser.getAttributeValue(null, "pkg");
869 try {
870 host.uid = getUidForPackage(host.packageName);
871 host.hostId = Integer.parseInt(
872 parser.getAttributeValue(null, "id"), 16);
873 mHosts.add(host);
874 } catch (PackageManager.NameNotFoundException ex) {
875 // Just ignore drop this entry, as if it has been uninstalled.
876 // We need to deal with this case because of safe mode, but there's
877 // a bug filed about it.
878 }
879 }
880 else if ("g".equals(tag)) {
881 GadgetId id = new GadgetId();
882 id.gadgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
883 if (id.gadgetId >= mNextGadgetId) {
884 mNextGadgetId = id.gadgetId + 1;
885 }
886
887 String providerString = parser.getAttributeValue(null, "p");
888 if (providerString != null) {
889 // there's no provider if it hasn't been bound yet.
890 // maybe we don't have to save this, but it brings the system
891 // to the state it was in.
892 int pIndex = Integer.parseInt(providerString, 16);
893 id.provider = loadedProviders.get(pIndex);
894 if (false) {
895 Log.d(TAG, "bound gadgetId=" + id.gadgetId + " to provider "
896 + pIndex + " which is " + id.provider);
897 }
898 if (id.provider == null) {
899 // This provider is gone. We just let the host figure out
900 // that this happened when it fails to load it.
901 continue;
902 }
903 }
904
905 int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
906 id.host = mHosts.get(hIndex);
907 if (id.host == null) {
908 // This host is gone.
909 continue;
910 }
911
912 if (id.provider != null) {
913 id.provider.instances.add(id);
914 }
915 id.host.instances.add(id);
916 mGadgetIds.add(id);
917 }
918 }
919 } while (type != XmlPullParser.END_DOCUMENT);
920 success = true;
921 } catch (NullPointerException e) {
922 Log.w(TAG, "failed parsing " + file, e);
923 } catch (NumberFormatException e) {
924 Log.w(TAG, "failed parsing " + file, e);
925 } catch (XmlPullParserException e) {
926 Log.w(TAG, "failed parsing " + file, e);
927 } catch (IOException e) {
928 Log.w(TAG, "failed parsing " + file, e);
929 } catch (IndexOutOfBoundsException e) {
930 Log.w(TAG, "failed parsing " + file, e);
931 }
932 try {
933 if (stream != null) {
934 stream.close();
935 }
936 } catch (IOException e) {
937 }
938
939 if (success) {
940 // delete any hosts that didn't manage to get connected (should happen)
941 // if it matters, they'll be reconnected.
942 final int N = mHosts.size();
943 for (int i=0; i<N; i++) {
944 pruneHostLocked(mHosts.get(i));
945 }
946 } else {
947 // failed reading, clean up
948 mGadgetIds.clear();
949 mHosts.clear();
950 final int N = mInstalledProviders.size();
951 for (int i=0; i<N; i++) {
952 mInstalledProviders.get(i).instances.clear();
953 }
954 }
955 }
956
957 File savedStateTempFile() {
958 return new File("/data/system/" + SETTINGS_TMP_FILENAME);
959 //return new File(mContext.getFilesDir(), SETTINGS_FILENAME);
960 }
961
962 File savedStateRealFile() {
963 return new File("/data/system/" + SETTINGS_FILENAME);
964 //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME);
965 }
966
967 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
968 public void onReceive(Context context, Intent intent) {
969 String action = intent.getAction();
970 //Log.d(TAG, "received " + action);
971 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
972 sendInitialBroadcasts();
973 } else {
974 Uri uri = intent.getData();
975 if (uri == null) {
976 return;
977 }
978 String pkgName = uri.getSchemeSpecificPart();
979 if (pkgName == null) {
980 return;
981 }
982
983 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
984 synchronized (mGadgetIds) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800985 Bundle extras = intent.getExtras();
986 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
987 // The package was just upgraded
988 updateProvidersForPackageLocked(pkgName);
989 } else {
990 // The package was just added
991 addProvidersForPackageLocked(pkgName);
992 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800993 saveStateLocked();
994 }
995 }
996 else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800997 Bundle extras = intent.getExtras();
998 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
999 // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
1000 } else {
1001 synchronized (mGadgetIds) {
1002 removeProvidersForPackageLocked(pkgName);
1003 saveStateLocked();
1004 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001005 }
1006 }
1007 }
1008 }
1009 };
1010
1011 // TODO: If there's a better way of matching an intent filter against the
1012 // packages for a given package, use that.
1013 void addProvidersForPackageLocked(String pkgName) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001014 Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001015 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
1016 PackageManager.GET_META_DATA);
1017
1018 final int N = broadcastReceivers.size();
1019 for (int i=0; i<N; i++) {
1020 ResolveInfo ri = broadcastReceivers.get(i);
1021 ActivityInfo ai = ri.activityInfo;
1022
1023 if (pkgName.equals(ai.packageName)) {
1024 addProviderLocked(ri);
1025 }
1026 }
1027 }
1028
1029 // TODO: If there's a better way of matching an intent filter against the
1030 // packages for a given package, use that.
1031 void updateProvidersForPackageLocked(String pkgName) {
1032 HashSet<String> keep = new HashSet();
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001033 Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001034 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
1035 PackageManager.GET_META_DATA);
1036
1037 // add the missing ones and collect which ones to keep
1038 int N = broadcastReceivers.size();
1039 for (int i=0; i<N; i++) {
1040 ResolveInfo ri = broadcastReceivers.get(i);
1041 ActivityInfo ai = ri.activityInfo;
1042 if (pkgName.equals(ai.packageName)) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001043 ComponentName component = new ComponentName(ai.packageName, ai.name);
1044 Provider p = lookupProviderLocked(component);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001045 if (p == null) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001046 if (addProviderLocked(ri)) {
1047 keep.add(ai.name);
1048 }
1049 } else {
1050 Provider parsed = parseProviderInfoXml(component, ri);
1051 if (parsed != null) {
1052 keep.add(ai.name);
1053 // Use the new GadgetProviderInfo.
1054 GadgetProviderInfo oldInfo = p.info;
1055 p.info = parsed.info;
1056 // If it's enabled
1057 final int M = p.instances.size();
1058 if (M > 0) {
1059 int[] gadgetIds = getGadgetIds(p);
1060 // Reschedule for the new updatePeriodMillis (don't worry about handling
1061 // it specially if updatePeriodMillis didn't change because we just sent
1062 // an update, and the next one will be updatePeriodMillis from now).
1063 cancelBroadcasts(p);
1064 registerForBroadcastsLocked(p, gadgetIds);
1065 // If it's currently showing, call back with the new GadgetProviderInfo.
1066 for (int j=0; j<M; j++) {
1067 GadgetId id = p.instances.get(j);
1068 if (id.host != null && id.host.callbacks != null) {
1069 try {
1070 id.host.callbacks.providerChanged(id.gadgetId, p.info);
1071 } catch (RemoteException ex) {
1072 // It failed; remove the callback. No need to prune because
1073 // we know that this host is still referenced by this
1074 // instance.
1075 id.host.callbacks = null;
1076 }
1077 }
1078 }
1079 // Now that we've told the host, push out an update.
1080 sendUpdateIntentLocked(p, gadgetIds);
1081 }
1082 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001083 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001084 }
1085 }
1086
1087 // prune the ones we don't want to keep
1088 N = mInstalledProviders.size();
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001089 for (int i=N-1; i>=0; i--) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001090 Provider p = mInstalledProviders.get(i);
1091 if (pkgName.equals(p.info.provider.getPackageName())
1092 && !keep.contains(p.info.provider.getClassName())) {
1093 removeProviderLocked(i, p);
1094 }
1095 }
1096 }
1097
1098 void removeProvidersForPackageLocked(String pkgName) {
1099 int N = mInstalledProviders.size();
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001100 for (int i=N-1; i>=0; i--) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001101 Provider p = mInstalledProviders.get(i);
1102 if (pkgName.equals(p.info.provider.getPackageName())) {
1103 removeProviderLocked(i, p);
1104 }
1105 }
1106
1107 // Delete the hosts for this package too
1108 //
1109 // By now, we have removed any gadgets that were in any hosts here,
1110 // so we don't need to worry about sending DISABLE broadcasts to them.
1111 N = mHosts.size();
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001112 for (int i=N-1; i>=0; i--) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001113 Host host = mHosts.get(i);
1114 if (pkgName.equals(host.packageName)) {
1115 deleteHostLocked(host);
1116 }
1117 }
The Android Open Source Project22f7dfd2009-01-20 14:03:58 -08001118 }
1119}
1120