1 /* 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 17 package com.android.server; 18 19 import android.app.AlarmManager; 20 import android.app.PendingIntent; 21 import android.appwidget.AppWidgetManager; 22 import android.appwidget.AppWidgetProviderInfo; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.pm.ActivityInfo; 29 import android.content.pm.ApplicationInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.PackageInfo; 32 import android.content.pm.ResolveInfo; 33 import android.content.res.Resources; 34 import android.content.res.TypedArray; 35 import android.content.res.XmlResourceParser; 36 import android.net.Uri; 37 import android.os.Binder; 38 import android.os.Bundle; 39 import android.os.Process; 40 import android.os.RemoteException; 41 import android.os.SystemClock; 42 import android.util.AttributeSet; 43 import android.util.Slog; 44 import android.util.TypedValue; 45 import android.util.Xml; 46 import android.widget.RemoteViews; 47 48 import java.io.IOException; 49 import java.io.File; 50 import java.io.FileDescriptor; 51 import java.io.FileInputStream; 52 import java.io.FileOutputStream; 53 import java.io.PrintWriter; 54 import java.util.ArrayList; 55 import java.util.List; 56 import java.util.Locale; 57 import java.util.HashMap; 58 import java.util.HashSet; 59 60 import com.android.internal.appwidget.IAppWidgetService; 61 import com.android.internal.appwidget.IAppWidgetHost; 62 import com.android.internal.util.FastXmlSerializer; 63 64 import org.xmlpull.v1.XmlPullParser; 65 import org.xmlpull.v1.XmlPullParserException; 66 import org.xmlpull.v1.XmlSerializer; 67 68 class AppWidgetService extends IAppWidgetService.Stub 69 { 70 private static final String TAG = "AppWidgetService"; 71 72 private static final String SETTINGS_FILENAME = "appwidgets.xml"; 73 private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp"; 74 private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes 75 76 /* 77 * When identifying a Host or Provider based on the calling process, use the uid field. 78 * When identifying a Host or Provider based on a package manager broadcast, use the 79 * package given. 80 */ 81 82 static class Provider { 83 int uid; 84 AppWidgetProviderInfo info; 85 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>(); 86 PendingIntent broadcast; 87 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 88 89 int tag; // for use while saving state (the index) 90 } 91 92 static class Host { 93 int uid; 94 int hostId; 95 String packageName; 96 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>(); 97 IAppWidgetHost callbacks; 98 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 99 100 int tag; // for use while saving state (the index) 101 } 102 103 static class AppWidgetId { 104 int appWidgetId; 105 Provider provider; 106 RemoteViews views; 107 Host host; 108 } 109 110 Context mContext; 111 Locale mLocale; 112 PackageManager mPackageManager; 113 AlarmManager mAlarmManager; 114 ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>(); 115 int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1; 116 final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>(); 117 ArrayList<Host> mHosts = new ArrayList<Host>(); 118 boolean mSafeMode; 119 120 AppWidgetService(Context context) { 121 mContext = context; 122 mPackageManager = context.getPackageManager(); 123 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 124 } 125 126 public void systemReady(boolean safeMode) { 127 mSafeMode = safeMode; 128 129 loadAppWidgetList(); 130 loadStateLocked(); 131 132 // Register for the boot completed broadcast, so we can send the 133 // ENABLE broacasts. If we try to send them now, they time out, 134 // because the system isn't ready to handle them yet. 135 mContext.registerReceiver(mBroadcastReceiver, 136 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 137 138 // Register for configuration changes so we can update the names 139 // of the widgets when the locale changes. 140 mContext.registerReceiver(mBroadcastReceiver, 141 new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null); 142 143 // Register for broadcasts about package install, etc., so we can 144 // update the provider list. 145 IntentFilter filter = new IntentFilter(); 146 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 147 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 148 filter.addDataScheme("package"); 149 mContext.registerReceiver(mBroadcastReceiver, filter); 150 // Register for events related to sdcard installation. 151 IntentFilter sdFilter = new IntentFilter(); 152 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 153 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 154 mContext.registerReceiver(mBroadcastReceiver, sdFilter); 155 } 156 157 @Override 158 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 159 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 160 != PackageManager.PERMISSION_GRANTED) { 161 pw.println("Permission Denial: can't dump from from pid=" 162 + Binder.getCallingPid() 163 + ", uid=" + Binder.getCallingUid()); 164 return; 165 } 166 167 synchronized (mAppWidgetIds) { 168 int N = mInstalledProviders.size(); 169 pw.println("Providers:"); 170 for (int i=0; i<N; i++) { 171 Provider p = mInstalledProviders.get(i); 172 AppWidgetProviderInfo info = p.info; 173 pw.print(" ["); pw.print(i); pw.print("] provider "); 174 pw.print(info.provider.flattenToShortString()); 175 pw.println(':'); 176 pw.print(" min=("); pw.print(info.minWidth); 177 pw.print("x"); pw.print(info.minHeight); 178 pw.print(") updatePeriodMillis="); 179 pw.print(info.updatePeriodMillis); 180 pw.print(" initialLayout=#"); 181 pw.print(Integer.toHexString(info.initialLayout)); 182 pw.print(" zombie="); pw.println(p.zombie); 183 } 184 185 N = mAppWidgetIds.size(); 186 pw.println(" "); 187 pw.println("AppWidgetIds:"); 188 for (int i=0; i<N; i++) { 189 AppWidgetId id = mAppWidgetIds.get(i); 190 pw.print(" ["); pw.print(i); pw.print("] id="); 191 pw.println(id.appWidgetId); 192 pw.print(" hostId="); 193 pw.print(id.host.hostId); pw.print(' '); 194 pw.print(id.host.packageName); pw.print('/'); 195 pw.println(id.host.uid); 196 if (id.provider != null) { 197 pw.print(" provider="); 198 pw.println(id.provider.info.provider.flattenToShortString()); 199 } 200 if (id.host != null) { 201 pw.print(" host.callbacks="); pw.println(id.host.callbacks); 202 } 203 if (id.views != null) { 204 pw.print(" views="); pw.println(id.views); 205 } 206 } 207 208 N = mHosts.size(); 209 pw.println(" "); 210 pw.println("Hosts:"); 211 for (int i=0; i<N; i++) { 212 Host host = mHosts.get(i); 213 pw.print(" ["); pw.print(i); pw.print("] hostId="); 214 pw.print(host.hostId); pw.print(' '); 215 pw.print(host.packageName); pw.print('/'); 216 pw.print(host.uid); pw.println(':'); 217 pw.print(" callbacks="); pw.println(host.callbacks); 218 pw.print(" instances.size="); pw.print(host.instances.size()); 219 pw.print(" zombie="); pw.println(host.zombie); 220 } 221 } 222 } 223 224 public int allocateAppWidgetId(String packageName, int hostId) { 225 int callingUid = enforceCallingUid(packageName); 226 synchronized (mAppWidgetIds) { 227 int appWidgetId = mNextAppWidgetId++; 228 229 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); 230 231 AppWidgetId id = new AppWidgetId(); 232 id.appWidgetId = appWidgetId; 233 id.host = host; 234 235 host.instances.add(id); 236 mAppWidgetIds.add(id); 237 238 saveStateLocked(); 239 240 return appWidgetId; 241 } 242 } 243 244 public void deleteAppWidgetId(int appWidgetId) { 245 synchronized (mAppWidgetIds) { 246 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 247 if (id != null) { 248 deleteAppWidgetLocked(id); 249 saveStateLocked(); 250 } 251 } 252 } 253 254 public void deleteHost(int hostId) { 255 synchronized (mAppWidgetIds) { 256 int callingUid = getCallingUid(); 257 Host host = lookupHostLocked(callingUid, hostId); 258 if (host != null) { 259 deleteHostLocked(host); 260 saveStateLocked(); 261 } 262 } 263 } 264 265 public void deleteAllHosts() { 266 synchronized (mAppWidgetIds) { 267 int callingUid = getCallingUid(); 268 final int N = mHosts.size(); 269 boolean changed = false; 270 for (int i=N-1; i>=0; i--) { 271 Host host = mHosts.get(i); 272 if (host.uid == callingUid) { 273 deleteHostLocked(host); 274 changed = true; 275 } 276 } 277 if (changed) { 278 saveStateLocked(); 279 } 280 } 281 } 282 283 void deleteHostLocked(Host host) { 284 final int N = host.instances.size(); 285 for (int i=N-1; i>=0; i--) { 286 AppWidgetId id = host.instances.get(i); 287 deleteAppWidgetLocked(id); 288 } 289 host.instances.clear(); 290 mHosts.remove(host); 291 // it's gone or going away, abruptly drop the callback connection 292 host.callbacks = null; 293 } 294 295 void deleteAppWidgetLocked(AppWidgetId id) { 296 Host host = id.host; 297 host.instances.remove(id); 298 pruneHostLocked(host); 299 300 mAppWidgetIds.remove(id); 301 302 Provider p = id.provider; 303 if (p != null) { 304 p.instances.remove(id); 305 if (!p.zombie) { 306 // send the broacast saying that this appWidgetId has been deleted 307 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); 308 intent.setComponent(p.info.provider); 309 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); 310 mContext.sendBroadcast(intent); 311 if (p.instances.size() == 0) { 312 // cancel the future updates 313 cancelBroadcasts(p); 314 315 // send the broacast saying that the provider is not in use any more 316 intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); 317 intent.setComponent(p.info.provider); 318 mContext.sendBroadcast(intent); 319 } 320 } 321 } 322 } 323 324 void cancelBroadcasts(Provider p) { 325 if (p.broadcast != null) { 326 mAlarmManager.cancel(p.broadcast); 327 long token = Binder.clearCallingIdentity(); 328 try { 329 p.broadcast.cancel(); 330 } finally { 331 Binder.restoreCallingIdentity(token); 332 } 333 p.broadcast = null; 334 } 335 } 336 337 public void bindAppWidgetId(int appWidgetId, ComponentName provider) { 338 mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET, 339 "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider); 340 synchronized (mAppWidgetIds) { 341 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 342 if (id == null) { 343 throw new IllegalArgumentException("bad appWidgetId"); 344 } 345 if (id.provider != null) { 346 throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to " 347 + id.provider.info.provider); 348 } 349 Provider p = lookupProviderLocked(provider); 350 if (p == null) { 351 throw new IllegalArgumentException("not a appwidget provider: " + provider); 352 } 353 if (p.zombie) { 354 throw new IllegalArgumentException("can't bind to a 3rd party provider in" 355 + " safe mode: " + provider); 356 } 357 358 id.provider = p; 359 p.instances.add(id); 360 int instancesSize = p.instances.size(); 361 if (instancesSize == 1) { 362 // tell the provider that it's ready 363 sendEnableIntentLocked(p); 364 } 365 366 // send an update now -- We need this update now, and just for this appWidgetId. 367 // It's less critical when the next one happens, so when we schdule the next one, 368 // we add updatePeriodMillis to its start time. That time will have some slop, 369 // but that's okay. 370 sendUpdateIntentLocked(p, new int[] { appWidgetId }); 371 372 // schedule the future updates 373 registerForBroadcastsLocked(p, getAppWidgetIds(p)); 374 saveStateLocked(); 375 } 376 } 377 378 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { 379 synchronized (mAppWidgetIds) { 380 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 381 if (id != null && id.provider != null && !id.provider.zombie) { 382 return id.provider.info; 383 } 384 return null; 385 } 386 } 387 388 public RemoteViews getAppWidgetViews(int appWidgetId) { 389 synchronized (mAppWidgetIds) { 390 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 391 if (id != null) { 392 return id.views; 393 } 394 return null; 395 } 396 } 397 398 public List<AppWidgetProviderInfo> getInstalledProviders() { 399 synchronized (mAppWidgetIds) { 400 final int N = mInstalledProviders.size(); 401 ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N); 402 for (int i=0; i<N; i++) { 403 Provider p = mInstalledProviders.get(i); 404 if (!p.zombie) { 405 result.add(p.info); 406 } 407 } 408 return result; 409 } 410 } 411 412 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) { 413 if (appWidgetIds == null) { 414 return; 415 } 416 if (appWidgetIds.length == 0) { 417 return; 418 } 419 final int N = appWidgetIds.length; 420 421 synchronized (mAppWidgetIds) { 422 for (int i=0; i<N; i++) { 423 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 424 updateAppWidgetInstanceLocked(id, views); 425 } 426 } 427 } 428 429 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) { 430 synchronized (mAppWidgetIds) { 431 Provider p = lookupProviderLocked(provider); 432 if (p == null) { 433 Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider); 434 return; 435 } 436 ArrayList<AppWidgetId> instances = p.instances; 437 final int N = instances.size(); 438 for (int i=0; i<N; i++) { 439 AppWidgetId id = instances.get(i); 440 updateAppWidgetInstanceLocked(id, views); 441 } 442 } 443 } 444 445 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) { 446 // allow for stale appWidgetIds and other badness 447 // lookup also checks that the calling process can access the appWidgetId 448 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) 449 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { 450 id.views = views; 451 452 // is anyone listening? 453 if (id.host.callbacks != null) { 454 try { 455 // the lock is held, but this is a oneway call 456 id.host.callbacks.updateAppWidget(id.appWidgetId, views); 457 } catch (RemoteException e) { 458 // It failed; remove the callback. No need to prune because 459 // we know that this host is still referenced by this instance. 460 id.host.callbacks = null; 461 } 462 } 463 } 464 } 465 466 public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId, 467 List<RemoteViews> updatedViews) { 468 int callingUid = enforceCallingUid(packageName); 469 synchronized (mAppWidgetIds) { 470 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); 471 host.callbacks = callbacks; 472 473 updatedViews.clear(); 474 475 ArrayList<AppWidgetId> instances = host.instances; 476 int N = instances.size(); 477 int[] updatedIds = new int[N]; 478 for (int i=0; i<N; i++) { 479 AppWidgetId id = instances.get(i); 480 updatedIds[i] = id.appWidgetId; 481 updatedViews.add(id.views); 482 } 483 return updatedIds; 484 } 485 } 486 487 public void stopListening(int hostId) { 488 synchronized (mAppWidgetIds) { 489 Host host = lookupHostLocked(getCallingUid(), hostId); 490 if (host != null) { 491 host.callbacks = null; 492 pruneHostLocked(host); 493 } 494 } 495 } 496 497 boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) { 498 if (id.host.uid == callingUid) { 499 // Apps hosting the AppWidget have access to it. 500 return true; 501 } 502 if (id.provider != null && id.provider.uid == callingUid) { 503 // Apps providing the AppWidget have access to it (if the appWidgetId has been bound) 504 return true; 505 } 506 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET) 507 == PackageManager.PERMISSION_GRANTED) { 508 // Apps that can bind have access to all appWidgetIds. 509 return true; 510 } 511 // Nobody else can access it. 512 return false; 513 } 514 515 AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) { 516 int callingUid = getCallingUid(); 517 final int N = mAppWidgetIds.size(); 518 for (int i=0; i<N; i++) { 519 AppWidgetId id = mAppWidgetIds.get(i); 520 if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) { 521 return id; 522 } 523 } 524 return null; 525 } 526 527 Provider lookupProviderLocked(ComponentName provider) { 528 final String className = provider.getClassName(); 529 final int N = mInstalledProviders.size(); 530 for (int i=0; i<N; i++) { 531 Provider p = mInstalledProviders.get(i); 532 if (p.info.provider.equals(provider) || className.equals(p.info.oldName)) { 533 return p; 534 } 535 } 536 return null; 537 } 538 539 Host lookupHostLocked(int uid, int hostId) { 540 final int N = mHosts.size(); 541 for (int i=0; i<N; i++) { 542 Host h = mHosts.get(i); 543 if (h.uid == uid && h.hostId == hostId) { 544 return h; 545 } 546 } 547 return null; 548 } 549 550 Host lookupOrAddHostLocked(int uid, String packageName, int hostId) { 551 final int N = mHosts.size(); 552 for (int i=0; i<N; i++) { 553 Host h = mHosts.get(i); 554 if (h.hostId == hostId && h.packageName.equals(packageName)) { 555 return h; 556 } 557 } 558 Host host = new Host(); 559 host.packageName = packageName; 560 host.uid = uid; 561 host.hostId = hostId; 562 mHosts.add(host); 563 return host; 564 } 565 566 void pruneHostLocked(Host host) { 567 if (host.instances.size() == 0 && host.callbacks == null) { 568 mHosts.remove(host); 569 } 570 } 571 572 void loadAppWidgetList() { 573 PackageManager pm = mPackageManager; 574 575 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 576 List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent, 577 PackageManager.GET_META_DATA); 578 579 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 580 for (int i=0; i<N; i++) { 581 ResolveInfo ri = broadcastReceivers.get(i); 582 addProviderLocked(ri); 583 } 584 } 585 586 boolean addProviderLocked(ResolveInfo ri) { 587 Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName, 588 ri.activityInfo.name), ri); 589 if (p != null) { 590 mInstalledProviders.add(p); 591 return true; 592 } else { 593 return false; 594 } 595 } 596 597 void removeProviderLocked(int index, Provider p) { 598 int N = p.instances.size(); 599 for (int i=0; i<N; i++) { 600 AppWidgetId id = p.instances.get(i); 601 // Call back with empty RemoteViews 602 updateAppWidgetInstanceLocked(id, null); 603 // Stop telling the host about updates for this from now on 604 cancelBroadcasts(p); 605 // clear out references to this appWidgetId 606 id.host.instances.remove(id); 607 mAppWidgetIds.remove(id); 608 id.provider = null; 609 pruneHostLocked(id.host); 610 id.host = null; 611 } 612 p.instances.clear(); 613 mInstalledProviders.remove(index); 614 // no need to send the DISABLE broadcast, since the receiver is gone anyway 615 cancelBroadcasts(p); 616 } 617 618 void sendEnableIntentLocked(Provider p) { 619 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); 620 intent.setComponent(p.info.provider); 621 mContext.sendBroadcast(intent); 622 } 623 624 void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) { 625 if (appWidgetIds != null && appWidgetIds.length > 0) { 626 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 627 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 628 intent.setComponent(p.info.provider); 629 mContext.sendBroadcast(intent); 630 } 631 } 632 633 void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) { 634 if (p.info.updatePeriodMillis > 0) { 635 // if this is the first instance, set the alarm. otherwise, 636 // rely on the fact that we've already set it and that 637 // PendingIntent.getBroadcast will update the extras. 638 boolean alreadyRegistered = p.broadcast != null; 639 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 640 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 641 intent.setComponent(p.info.provider); 642 long token = Binder.clearCallingIdentity(); 643 try { 644 p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent, 645 PendingIntent.FLAG_UPDATE_CURRENT); 646 } finally { 647 Binder.restoreCallingIdentity(token); 648 } 649 if (!alreadyRegistered) { 650 long period = p.info.updatePeriodMillis; 651 if (period < MIN_UPDATE_PERIOD) { 652 period = MIN_UPDATE_PERIOD; 653 } 654 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 655 SystemClock.elapsedRealtime() + period, period, p.broadcast); 656 } 657 } 658 } 659 660 static int[] getAppWidgetIds(Provider p) { 661 int instancesSize = p.instances.size(); 662 int appWidgetIds[] = new int[instancesSize]; 663 for (int i=0; i<instancesSize; i++) { 664 appWidgetIds[i] = p.instances.get(i).appWidgetId; 665 } 666 return appWidgetIds; 667 } 668 669 public int[] getAppWidgetIds(ComponentName provider) { 670 synchronized (mAppWidgetIds) { 671 Provider p = lookupProviderLocked(provider); 672 if (p != null && getCallingUid() == p.uid) { 673 return getAppWidgetIds(p); 674 } else { 675 return new int[0]; 676 } 677 } 678 } 679 680 private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) { 681 Provider p = null; 682 683 ActivityInfo activityInfo = ri.activityInfo; 684 XmlResourceParser parser = null; 685 try { 686 parser = activityInfo.loadXmlMetaData(mPackageManager, 687 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); 688 if (parser == null) { 689 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for " 690 + "AppWidget provider '" + component + '\''); 691 return null; 692 } 693 694 AttributeSet attrs = Xml.asAttributeSet(parser); 695 696 int type; 697 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 698 && type != XmlPullParser.START_TAG) { 699 // drain whitespace, comments, etc. 700 } 701 702 String nodeName = parser.getName(); 703 if (!"appwidget-provider".equals(nodeName)) { 704 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for" 705 + " AppWidget provider '" + component + '\''); 706 return null; 707 } 708 709 p = new Provider(); 710 AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo(); 711 // If metaData was null, we would have returned earlier when getting 712 // the parser No need to do the check here 713 info.oldName = activityInfo.metaData.getString( 714 AppWidgetManager.META_DATA_APPWIDGET_OLD_NAME); 715 716 info.provider = component; 717 p.uid = activityInfo.applicationInfo.uid; 718 719 Resources res = mPackageManager.getResourcesForApplication( 720 activityInfo.applicationInfo); 721 722 TypedArray sa = res.obtainAttributes(attrs, 723 com.android.internal.R.styleable.AppWidgetProviderInfo); 724 725 // These dimensions has to be resolved in the application's context. 726 // We simply send back the raw complex data, which will be 727 // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}. 728 TypedValue value = sa.peekValue( 729 com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth); 730 info.minWidth = value != null ? value.data : 0; 731 value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight); 732 info.minHeight = value != null ? value.data : 0; 733 734 info.updatePeriodMillis = sa.getInt( 735 com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0); 736 info.initialLayout = sa.getResourceId( 737 com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0); 738 String className = sa.getString( 739 com.android.internal.R.styleable.AppWidgetProviderInfo_configure); 740 if (className != null) { 741 info.configure = new ComponentName(component.getPackageName(), className); 742 } 743 info.label = activityInfo.loadLabel(mPackageManager).toString(); 744 info.icon = ri.getIconResource(); 745 sa.recycle(); 746 } catch (Exception e) { 747 // Ok to catch Exception here, because anything going wrong because 748 // of what a client process passes to us should not be fatal for the 749 // system process. 750 Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e); 751 return null; 752 } finally { 753 if (parser != null) parser.close(); 754 } 755 return p; 756 } 757 758 int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException { 759 PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0); 760 if (pkgInfo == null || pkgInfo.applicationInfo == null) { 761 throw new PackageManager.NameNotFoundException(); 762 } 763 return pkgInfo.applicationInfo.uid; 764 } 765 766 int enforceCallingUid(String packageName) throws IllegalArgumentException { 767 int callingUid = getCallingUid(); 768 int packageUid; 769 try { 770 packageUid = getUidForPackage(packageName); 771 } catch (PackageManager.NameNotFoundException ex) { 772 throw new IllegalArgumentException("packageName and uid don't match packageName=" 773 + packageName); 774 } 775 if (callingUid != packageUid && Process.supportsProcesses()) { 776 throw new IllegalArgumentException("packageName and uid don't match packageName=" 777 + packageName); 778 } 779 return callingUid; 780 } 781 782 void sendInitialBroadcasts() { 783 synchronized (mAppWidgetIds) { 784 final int N = mInstalledProviders.size(); 785 for (int i=0; i<N; i++) { 786 Provider p = mInstalledProviders.get(i); 787 if (p.instances.size() > 0) { 788 sendEnableIntentLocked(p); 789 int[] appWidgetIds = getAppWidgetIds(p); 790 sendUpdateIntentLocked(p, appWidgetIds); 791 registerForBroadcastsLocked(p, appWidgetIds); 792 } 793 } 794 } 795 } 796 797 // only call from initialization -- it assumes that the data structures are all empty 798 void loadStateLocked() { 799 File temp = savedStateTempFile(); 800 File real = savedStateRealFile(); 801 802 // prefer the real file. If it doesn't exist, use the temp one, and then copy it to the 803 // real one. if there is both a real file and a temp one, assume that the temp one isn't 804 // fully written and delete it. 805 if (real.exists()) { 806 readStateFromFileLocked(real); 807 if (temp.exists()) { 808 //noinspection ResultOfMethodCallIgnored 809 temp.delete(); 810 } 811 } else if (temp.exists()) { 812 readStateFromFileLocked(temp); 813 //noinspection ResultOfMethodCallIgnored 814 temp.renameTo(real); 815 } 816 } 817 818 void saveStateLocked() { 819 File temp = savedStateTempFile(); 820 File real = savedStateRealFile(); 821 822 if (!real.exists()) { 823 // If the real one doesn't exist, it's either because this is the first time 824 // or because something went wrong while copying them. In this case, we can't 825 // trust anything that's in temp. In order to have the loadState code not 826 // use the temporary one until it's fully written, create an empty file 827 // for real, which will we'll shortly delete. 828 try { 829 //noinspection ResultOfMethodCallIgnored 830 real.createNewFile(); 831 } catch (IOException e) { 832 // Ignore 833 } 834 } 835 836 if (temp.exists()) { 837 //noinspection ResultOfMethodCallIgnored 838 temp.delete(); 839 } 840 841 if (!writeStateToFileLocked(temp)) { 842 Slog.w(TAG, "Failed to persist new settings"); 843 return; 844 } 845 846 //noinspection ResultOfMethodCallIgnored 847 real.delete(); 848 //noinspection ResultOfMethodCallIgnored 849 temp.renameTo(real); 850 } 851 852 boolean writeStateToFileLocked(File file) { 853 FileOutputStream stream = null; 854 int N; 855 856 try { 857 stream = new FileOutputStream(file, false); 858 XmlSerializer out = new FastXmlSerializer(); 859 out.setOutput(stream, "utf-8"); 860 out.startDocument(null, true); 861 862 863 out.startTag(null, "gs"); 864 865 int providerIndex = 0; 866 N = mInstalledProviders.size(); 867 for (int i=0; i<N; i++) { 868 Provider p = mInstalledProviders.get(i); 869 if (p.instances.size() > 0) { 870 out.startTag(null, "p"); 871 out.attribute(null, "pkg", p.info.provider.getPackageName()); 872 out.attribute(null, "cl", p.info.provider.getClassName()); 873 out.endTag(null, "p"); 874 p.tag = providerIndex; 875 providerIndex++; 876 } 877 } 878 879 N = mHosts.size(); 880 for (int i=0; i<N; i++) { 881 Host host = mHosts.get(i); 882 out.startTag(null, "h"); 883 out.attribute(null, "pkg", host.packageName); 884 out.attribute(null, "id", Integer.toHexString(host.hostId)); 885 out.endTag(null, "h"); 886 host.tag = i; 887 } 888 889 N = mAppWidgetIds.size(); 890 for (int i=0; i<N; i++) { 891 AppWidgetId id = mAppWidgetIds.get(i); 892 out.startTag(null, "g"); 893 out.attribute(null, "id", Integer.toHexString(id.appWidgetId)); 894 out.attribute(null, "h", Integer.toHexString(id.host.tag)); 895 if (id.provider != null) { 896 out.attribute(null, "p", Integer.toHexString(id.provider.tag)); 897 } 898 out.endTag(null, "g"); 899 } 900 901 out.endTag(null, "gs"); 902 903 out.endDocument(); 904 stream.close(); 905 return true; 906 } catch (IOException e) { 907 try { 908 if (stream != null) { 909 stream.close(); 910 } 911 } catch (IOException ex) { 912 // Ignore 913 } 914 if (file.exists()) { 915 //noinspection ResultOfMethodCallIgnored 916 file.delete(); 917 } 918 return false; 919 } 920 } 921 922 void readStateFromFileLocked(File file) { 923 FileInputStream stream = null; 924 925 boolean success = false; 926 927 try { 928 stream = new FileInputStream(file); 929 XmlPullParser parser = Xml.newPullParser(); 930 parser.setInput(stream, null); 931 932 int type; 933 int providerIndex = 0; 934 HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>(); 935 do { 936 type = parser.next(); 937 if (type == XmlPullParser.START_TAG) { 938 String tag = parser.getName(); 939 if ("p".equals(tag)) { 940 // TODO: do we need to check that this package has the same signature 941 // as before? 942 String pkg = parser.getAttributeValue(null, "pkg"); 943 String cl = parser.getAttributeValue(null, "cl"); 944 945 final PackageManager packageManager = mContext.getPackageManager(); 946 try { 947 packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0); 948 } catch (PackageManager.NameNotFoundException e) { 949 String[] pkgs = packageManager.currentToCanonicalPackageNames( 950 new String[] { pkg }); 951 pkg = pkgs[0]; 952 } 953 954 Provider p = lookupProviderLocked(new ComponentName(pkg, cl)); 955 if (p == null && mSafeMode) { 956 // if we're in safe mode, make a temporary one 957 p = new Provider(); 958 p.info = new AppWidgetProviderInfo(); 959 p.info.provider = new ComponentName(pkg, cl); 960 p.zombie = true; 961 mInstalledProviders.add(p); 962 } 963 if (p != null) { 964 // if it wasn't uninstalled or something 965 loadedProviders.put(providerIndex, p); 966 } 967 providerIndex++; 968 } 969 else if ("h".equals(tag)) { 970 Host host = new Host(); 971 972 // TODO: do we need to check that this package has the same signature 973 // as before? 974 host.packageName = parser.getAttributeValue(null, "pkg"); 975 try { 976 host.uid = getUidForPackage(host.packageName); 977 } catch (PackageManager.NameNotFoundException ex) { 978 host.zombie = true; 979 } 980 if (!host.zombie || mSafeMode) { 981 // In safe mode, we don't discard the hosts we don't recognize 982 // so that they're not pruned from our list. Otherwise, we do. 983 host.hostId = Integer.parseInt( 984 parser.getAttributeValue(null, "id"), 16); 985 mHosts.add(host); 986 } 987 } 988 else if ("g".equals(tag)) { 989 AppWidgetId id = new AppWidgetId(); 990 id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16); 991 if (id.appWidgetId >= mNextAppWidgetId) { 992 mNextAppWidgetId = id.appWidgetId + 1; 993 } 994 995 String providerString = parser.getAttributeValue(null, "p"); 996 if (providerString != null) { 997 // there's no provider if it hasn't been bound yet. 998 // maybe we don't have to save this, but it brings the system 999 // to the state it was in. 1000 int pIndex = Integer.parseInt(providerString, 16); 1001 id.provider = loadedProviders.get(pIndex); 1002 if (false) { 1003 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider " 1004 + pIndex + " which is " + id.provider); 1005 } 1006 if (id.provider == null) { 1007 // This provider is gone. We just let the host figure out 1008 // that this happened when it fails to load it. 1009 continue; 1010 } 1011 } 1012 1013 int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16); 1014 id.host = mHosts.get(hIndex); 1015 if (id.host == null) { 1016 // This host is gone. 1017 continue; 1018 } 1019 1020 if (id.provider != null) { 1021 id.provider.instances.add(id); 1022 } 1023 id.host.instances.add(id); 1024 mAppWidgetIds.add(id); 1025 } 1026 } 1027 } while (type != XmlPullParser.END_DOCUMENT); 1028 success = true; 1029 } catch (NullPointerException e) { 1030 Slog.w(TAG, "failed parsing " + file, e); 1031 } catch (NumberFormatException e) { 1032 Slog.w(TAG, "failed parsing " + file, e); 1033 } catch (XmlPullParserException e) { 1034 Slog.w(TAG, "failed parsing " + file, e); 1035 } catch (IOException e) { 1036 Slog.w(TAG, "failed parsing " + file, e); 1037 } catch (IndexOutOfBoundsException e) { 1038 Slog.w(TAG, "failed parsing " + file, e); 1039 } 1040 try { 1041 if (stream != null) { 1042 stream.close(); 1043 } 1044 } catch (IOException e) { 1045 // Ignore 1046 } 1047 1048 if (success) { 1049 // delete any hosts that didn't manage to get connected (should happen) 1050 // if it matters, they'll be reconnected. 1051 for (int i=mHosts.size()-1; i>=0; i--) { 1052 pruneHostLocked(mHosts.get(i)); 1053 } 1054 } else { 1055 // failed reading, clean up 1056 mAppWidgetIds.clear(); 1057 mHosts.clear(); 1058 final int N = mInstalledProviders.size(); 1059 for (int i=0; i<N; i++) { 1060 mInstalledProviders.get(i).instances.clear(); 1061 } 1062 } 1063 } 1064 1065 File savedStateTempFile() { 1066 return new File("/data/system/" + SETTINGS_TMP_FILENAME); 1067 //return new File(mContext.getFilesDir(), SETTINGS_FILENAME); 1068 } 1069 1070 File savedStateRealFile() { 1071 return new File("/data/system/" + SETTINGS_FILENAME); 1072 //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME); 1073 } 1074 1075 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1076 public void onReceive(Context context, Intent intent) { 1077 String action = intent.getAction(); 1078 //Slog.d(TAG, "received " + action); 1079 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 1080 sendInitialBroadcasts(); 1081 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { 1082 Locale revised = Locale.getDefault(); 1083 if (revised == null || mLocale == null || 1084 !(revised.equals(mLocale))) { 1085 mLocale = revised; 1086 1087 synchronized (mAppWidgetIds) { 1088 int N = mInstalledProviders.size(); 1089 for (int i=N-1; i>=0; i--) { 1090 Provider p = mInstalledProviders.get(i); 1091 String pkgName = p.info.provider.getPackageName(); 1092 updateProvidersForPackageLocked(pkgName); 1093 } 1094 saveStateLocked(); 1095 } 1096 } 1097 } else { 1098 boolean added = false; 1099 String pkgList[] = null; 1100 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 1101 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1102 added = true; 1103 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 1104 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1105 added = false; 1106 } else { 1107 Uri uri = intent.getData(); 1108 if (uri == null) { 1109 return; 1110 } 1111 String pkgName = uri.getSchemeSpecificPart(); 1112 if (pkgName == null) { 1113 return; 1114 } 1115 pkgList = new String[] { pkgName }; 1116 added = Intent.ACTION_PACKAGE_ADDED.equals(action); 1117 } 1118 if (pkgList == null || pkgList.length == 0) { 1119 return; 1120 } 1121 if (added) { 1122 synchronized (mAppWidgetIds) { 1123 Bundle extras = intent.getExtras(); 1124 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { 1125 for (String pkgName : pkgList) { 1126 // The package was just upgraded 1127 updateProvidersForPackageLocked(pkgName); 1128 } 1129 } else { 1130 // The package was just added 1131 for (String pkgName : pkgList) { 1132 addProvidersForPackageLocked(pkgName); 1133 } 1134 } 1135 saveStateLocked(); 1136 } 1137 } else { 1138 Bundle extras = intent.getExtras(); 1139 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { 1140 // The package is being updated. We'll receive a PACKAGE_ADDED shortly. 1141 } else { 1142 synchronized (mAppWidgetIds) { 1143 for (String pkgName : pkgList) { 1144 removeProvidersForPackageLocked(pkgName); 1145 saveStateLocked(); 1146 } 1147 } 1148 } 1149 } 1150 } 1151 } 1152 }; 1153 1154 void addProvidersForPackageLocked(String pkgName) { 1155 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1156 intent.setPackage(pkgName); 1157 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, 1158 PackageManager.GET_META_DATA); 1159 1160 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1161 for (int i=0; i<N; i++) { 1162 ResolveInfo ri = broadcastReceivers.get(i); 1163 ActivityInfo ai = ri.activityInfo; 1164 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1165 continue; 1166 } 1167 if (pkgName.equals(ai.packageName)) { 1168 addProviderLocked(ri); 1169 } 1170 } 1171 } 1172 1173 void updateProvidersForPackageLocked(String pkgName) { 1174 HashSet<String> keep = new HashSet<String>(); 1175 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1176 intent.setPackage(pkgName); 1177 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, 1178 PackageManager.GET_META_DATA); 1179 1180 // add the missing ones and collect which ones to keep 1181 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1182 for (int i=0; i<N; i++) { 1183 ResolveInfo ri = broadcastReceivers.get(i); 1184 ActivityInfo ai = ri.activityInfo; 1185 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1186 continue; 1187 } 1188 if (pkgName.equals(ai.packageName)) { 1189 ComponentName component = new ComponentName(ai.packageName, ai.name); 1190 Provider p = lookupProviderLocked(component); 1191 if (p == null) { 1192 if (addProviderLocked(ri)) { 1193 keep.add(ai.name); 1194 } 1195 } else { 1196 Provider parsed = parseProviderInfoXml(component, ri); 1197 if (parsed != null) { 1198 keep.add(ai.name); 1199 // Use the new AppWidgetProviderInfo. 1200 p.info = parsed.info; 1201 // If it's enabled 1202 final int M = p.instances.size(); 1203 if (M > 0) { 1204 int[] appWidgetIds = getAppWidgetIds(p); 1205 // Reschedule for the new updatePeriodMillis (don't worry about handling 1206 // it specially if updatePeriodMillis didn't change because we just sent 1207 // an update, and the next one will be updatePeriodMillis from now). 1208 cancelBroadcasts(p); 1209 registerForBroadcastsLocked(p, appWidgetIds); 1210 // If it's currently showing, call back with the new AppWidgetProviderInfo. 1211 for (int j=0; j<M; j++) { 1212 AppWidgetId id = p.instances.get(j); 1213 id.views = null; 1214 if (id.host != null && id.host.callbacks != null) { 1215 try { 1216 id.host.callbacks.providerChanged(id.appWidgetId, p.info); 1217 } catch (RemoteException ex) { 1218 // It failed; remove the callback. No need to prune because 1219 // we know that this host is still referenced by this 1220 // instance. 1221 id.host.callbacks = null; 1222 } 1223 } 1224 } 1225 // Now that we've told the host, push out an update. 1226 sendUpdateIntentLocked(p, appWidgetIds); 1227 } 1228 } 1229 } 1230 } 1231 } 1232 1233 // prune the ones we don't want to keep 1234 N = mInstalledProviders.size(); 1235 for (int i=N-1; i>=0; i--) { 1236 Provider p = mInstalledProviders.get(i); 1237 if (pkgName.equals(p.info.provider.getPackageName()) 1238 && !keep.contains(p.info.provider.getClassName())) { 1239 removeProviderLocked(i, p); 1240 } 1241 } 1242 } 1243 1244 void removeProvidersForPackageLocked(String pkgName) { 1245 int N = mInstalledProviders.size(); 1246 for (int i=N-1; i>=0; i--) { 1247 Provider p = mInstalledProviders.get(i); 1248 if (pkgName.equals(p.info.provider.getPackageName())) { 1249 removeProviderLocked(i, p); 1250 } 1251 } 1252 1253 // Delete the hosts for this package too 1254 // 1255 // By now, we have removed any AppWidgets that were in any hosts here, 1256 // so we don't need to worry about sending DISABLE broadcasts to them. 1257 N = mHosts.size(); 1258 for (int i=N-1; i>=0; i--) { 1259 Host host = mHosts.get(i); 1260 if (pkgName.equals(host.packageName)) { 1261 deleteHostLocked(host); 1262 } 1263 } 1264 } 1265 } 1266 1267