blob: 0d142da549ccdeb5f6facf79c3084d0dd1b03570 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
19import com.android.internal.app.ResolverActivity;
20import com.android.internal.util.FastXmlSerializer;
21import com.android.internal.util.XmlUtils;
Satish Sampath8dbe6122009-06-02 23:35:54 +010022import com.android.server.PackageManagerService.PreferredActivity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
24import org.xmlpull.v1.XmlPullParser;
25import org.xmlpull.v1.XmlPullParserException;
26import org.xmlpull.v1.XmlSerializer;
27
28import android.app.ActivityManagerNative;
29import android.app.IActivityManager;
30import android.app.PendingIntent;
31import android.app.PendingIntent.CanceledException;
32import android.content.ComponentName;
33import android.content.ContentResolver;
34import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.content.pm.ActivityInfo;
38import android.content.pm.ApplicationInfo;
39import android.content.pm.ComponentInfo;
40import android.content.pm.IPackageDataObserver;
41import android.content.pm.IPackageDeleteObserver;
42import android.content.pm.IPackageInstallObserver;
43import android.content.pm.IPackageManager;
44import android.content.pm.IPackageStatsObserver;
45import android.content.pm.InstrumentationInfo;
46import android.content.pm.PackageInfo;
47import android.content.pm.PackageManager;
48import android.content.pm.PackageStats;
49import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
50import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
51import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
52import static android.content.pm.PackageManager.PKG_INSTALL_COMPLETE;
53import static android.content.pm.PackageManager.PKG_INSTALL_INCOMPLETE;
54import android.content.pm.PackageParser;
55import android.content.pm.PermissionInfo;
56import android.content.pm.PermissionGroupInfo;
57import android.content.pm.ProviderInfo;
58import android.content.pm.ResolveInfo;
59import android.content.pm.ServiceInfo;
60import android.content.pm.Signature;
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -070061import android.content.res.CompatibilityInfo;
62import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.net.Uri;
64import android.os.Binder;
Dianne Hackborn851a5412009-05-08 12:06:44 -070065import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.os.Bundle;
67import android.os.HandlerThread;
68import android.os.Parcel;
69import android.os.RemoteException;
70import android.os.Environment;
71import android.os.FileObserver;
72import android.os.FileUtils;
73import android.os.Handler;
74import android.os.ParcelFileDescriptor;
75import android.os.Process;
76import android.os.ServiceManager;
77import android.os.SystemClock;
78import android.os.SystemProperties;
79import android.util.*;
80import android.view.Display;
81import android.view.WindowManager;
82
83import java.io.File;
84import java.io.FileDescriptor;
85import java.io.FileInputStream;
86import java.io.FileNotFoundException;
87import java.io.FileOutputStream;
88import java.io.FileReader;
89import java.io.FilenameFilter;
90import java.io.IOException;
91import java.io.InputStream;
92import java.io.PrintWriter;
93import java.util.ArrayList;
94import java.util.Arrays;
95import java.util.Collections;
96import java.util.Comparator;
97import java.util.Enumeration;
98import java.util.HashMap;
99import java.util.HashSet;
100import java.util.Iterator;
101import java.util.List;
102import java.util.Map;
103import java.util.Set;
104import java.util.zip.ZipEntry;
105import java.util.zip.ZipFile;
106import java.util.zip.ZipOutputStream;
107
108class PackageManagerService extends IPackageManager.Stub {
109 private static final String TAG = "PackageManager";
110 private static final boolean DEBUG_SETTINGS = false;
111 private static final boolean DEBUG_PREFERRED = false;
112
113 private static final boolean MULTIPLE_APPLICATION_UIDS = true;
114 private static final int RADIO_UID = Process.PHONE_UID;
115 private static final int FIRST_APPLICATION_UID =
116 Process.FIRST_APPLICATION_UID;
117 private static final int MAX_APPLICATION_UIDS = 1000;
118
119 private static final boolean SHOW_INFO = false;
120
121 private static final boolean GET_CERTIFICATES = true;
122
123 private static final int REMOVE_EVENTS =
124 FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM;
125 private static final int ADD_EVENTS =
126 FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO;
127
128 private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS;
129
130 static final int SCAN_MONITOR = 1<<0;
131 static final int SCAN_NO_DEX = 1<<1;
132 static final int SCAN_FORCE_DEX = 1<<2;
133 static final int SCAN_UPDATE_SIGNATURE = 1<<3;
134 static final int SCAN_FORWARD_LOCKED = 1<<4;
The Android Open Source Project10592532009-03-18 17:39:46 -0700135 static final int SCAN_NEW_INSTALL = 1<<5;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
137 static final int LOG_BOOT_PROGRESS_PMS_START = 3060;
138 static final int LOG_BOOT_PROGRESS_PMS_SYSTEM_SCAN_START = 3070;
139 static final int LOG_BOOT_PROGRESS_PMS_DATA_SCAN_START = 3080;
140 static final int LOG_BOOT_PROGRESS_PMS_SCAN_END = 3090;
141 static final int LOG_BOOT_PROGRESS_PMS_READY = 3100;
142
143 final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
144 Process.THREAD_PRIORITY_BACKGROUND);
145 final Handler mHandler;
146
Dianne Hackborn851a5412009-05-08 12:06:44 -0700147 final int mSdkVersion = Build.VERSION.SDK_INT;
148 final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME)
149 ? null : Build.VERSION.CODENAME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150
151 final Context mContext;
152 final boolean mFactoryTest;
153 final DisplayMetrics mMetrics;
154 final int mDefParseFlags;
155 final String[] mSeparateProcesses;
156
157 // This is where all application persistent data goes.
158 final File mAppDataDir;
159
160 // This is the object monitoring the framework dir.
161 final FileObserver mFrameworkInstallObserver;
162
163 // This is the object monitoring the system app dir.
164 final FileObserver mSystemInstallObserver;
165
166 // This is the object monitoring mAppInstallDir.
167 final FileObserver mAppInstallObserver;
168
169 // This is the object monitoring mDrmAppPrivateInstallDir.
170 final FileObserver mDrmAppInstallObserver;
171
172 // Used for priviledge escalation. MUST NOT BE CALLED WITH mPackages
173 // LOCK HELD. Can be called with mInstallLock held.
174 final Installer mInstaller;
175
176 final File mFrameworkDir;
177 final File mSystemAppDir;
178 final File mAppInstallDir;
179
180 // Directory containing the private parts (e.g. code and non-resource assets) of forward-locked
181 // apps.
182 final File mDrmAppPrivateInstallDir;
183
184 // ----------------------------------------------------------------
185
186 // Lock for state used when installing and doing other long running
187 // operations. Methods that must be called with this lock held have
188 // the prefix "LI".
189 final Object mInstallLock = new Object();
190
191 // These are the directories in the 3rd party applications installed dir
192 // that we have currently loaded packages from. Keys are the application's
193 // installed zip file (absolute codePath), and values are Package.
194 final HashMap<String, PackageParser.Package> mAppDirs =
195 new HashMap<String, PackageParser.Package>();
196
197 // Information for the parser to write more useful error messages.
198 File mScanningPath;
199 int mLastScanError;
200
201 final int[] mOutPermissions = new int[3];
202
203 // ----------------------------------------------------------------
204
205 // Keys are String (package name), values are Package. This also serves
206 // as the lock for the global state. Methods that must be called with
207 // this lock held have the prefix "LP".
208 final HashMap<String, PackageParser.Package> mPackages =
209 new HashMap<String, PackageParser.Package>();
210
211 final Settings mSettings;
212 boolean mRestoredSettings;
213 boolean mReportedUidError;
214
215 // Group-ids that are given to all packages as read from etc/permissions/*.xml.
216 int[] mGlobalGids;
217
218 // These are the built-in uid -> permission mappings that were read from the
219 // etc/permissions.xml file.
220 final SparseArray<HashSet<String>> mSystemPermissions =
221 new SparseArray<HashSet<String>>();
222
223 // These are the built-in shared libraries that were read from the
224 // etc/permissions.xml file.
225 final HashMap<String, String> mSharedLibraries = new HashMap<String, String>();
226
227 // All available activities, for your resolving pleasure.
228 final ActivityIntentResolver mActivities =
229 new ActivityIntentResolver();
230
231 // All available receivers, for your resolving pleasure.
232 final ActivityIntentResolver mReceivers =
233 new ActivityIntentResolver();
234
235 // All available services, for your resolving pleasure.
236 final ServiceIntentResolver mServices = new ServiceIntentResolver();
237
238 // Keys are String (provider class name), values are Provider.
239 final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent =
240 new HashMap<ComponentName, PackageParser.Provider>();
241
242 // Mapping from provider base names (first directory in content URI codePath)
243 // to the provider information.
244 final HashMap<String, PackageParser.Provider> mProviders =
245 new HashMap<String, PackageParser.Provider>();
246
247 // Mapping from instrumentation class names to info about them.
248 final HashMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
249 new HashMap<ComponentName, PackageParser.Instrumentation>();
250
251 // Mapping from permission names to info about them.
252 final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups =
253 new HashMap<String, PackageParser.PermissionGroup>();
254
255 boolean mSystemReady;
256 boolean mSafeMode;
257 boolean mHasSystemUidErrors;
258
259 ApplicationInfo mAndroidApplication;
260 final ActivityInfo mResolveActivity = new ActivityInfo();
261 final ResolveInfo mResolveInfo = new ResolveInfo();
262 ComponentName mResolveComponentName;
263 PackageParser.Package mPlatformPackage;
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700264 private boolean mCompatibilityModeEnabled = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265
266 public static final IPackageManager main(Context context, boolean factoryTest) {
267 PackageManagerService m = new PackageManagerService(context, factoryTest);
268 ServiceManager.addService("package", m);
269 return m;
270 }
271
272 static String[] splitString(String str, char sep) {
273 int count = 1;
274 int i = 0;
275 while ((i=str.indexOf(sep, i)) >= 0) {
276 count++;
277 i++;
278 }
279
280 String[] res = new String[count];
281 i=0;
282 count = 0;
283 int lastI=0;
284 while ((i=str.indexOf(sep, i)) >= 0) {
285 res[count] = str.substring(lastI, i);
286 count++;
287 i++;
288 lastI = i;
289 }
290 res[count] = str.substring(lastI, str.length());
291 return res;
292 }
293
294 public PackageManagerService(Context context, boolean factoryTest) {
295 EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_START,
296 SystemClock.uptimeMillis());
297
298 if (mSdkVersion <= 0) {
299 Log.w(TAG, "**** ro.build.version.sdk not set!");
300 }
301
302 mContext = context;
303 mFactoryTest = factoryTest;
304 mMetrics = new DisplayMetrics();
305 mSettings = new Settings();
306 mSettings.addSharedUserLP("android.uid.system",
307 Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
308 mSettings.addSharedUserLP("android.uid.phone",
309 MULTIPLE_APPLICATION_UIDS
310 ? RADIO_UID : FIRST_APPLICATION_UID,
311 ApplicationInfo.FLAG_SYSTEM);
312
313 String separateProcesses = SystemProperties.get("debug.separate_processes");
314 if (separateProcesses != null && separateProcesses.length() > 0) {
315 if ("*".equals(separateProcesses)) {
316 mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
317 mSeparateProcesses = null;
318 Log.w(TAG, "Running with debug.separate_processes: * (ALL)");
319 } else {
320 mDefParseFlags = 0;
321 mSeparateProcesses = separateProcesses.split(",");
322 Log.w(TAG, "Running with debug.separate_processes: "
323 + separateProcesses);
324 }
325 } else {
326 mDefParseFlags = 0;
327 mSeparateProcesses = null;
328 }
329
330 Installer installer = new Installer();
331 // Little hacky thing to check if installd is here, to determine
332 // whether we are running on the simulator and thus need to take
333 // care of building the /data file structure ourself.
334 // (apparently the sim now has a working installer)
335 if (installer.ping() && Process.supportsProcesses()) {
336 mInstaller = installer;
337 } else {
338 mInstaller = null;
339 }
340
341 WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
342 Display d = wm.getDefaultDisplay();
343 d.getMetrics(mMetrics);
344
345 synchronized (mInstallLock) {
346 synchronized (mPackages) {
347 mHandlerThread.start();
348 mHandler = new Handler(mHandlerThread.getLooper());
349
350 File dataDir = Environment.getDataDirectory();
351 mAppDataDir = new File(dataDir, "data");
352 mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
353
354 if (mInstaller == null) {
355 // Make sure these dirs exist, when we are running in
356 // the simulator.
357 // Make a wide-open directory for random misc stuff.
358 File miscDir = new File(dataDir, "misc");
359 miscDir.mkdirs();
360 mAppDataDir.mkdirs();
361 mDrmAppPrivateInstallDir.mkdirs();
362 }
363
364 readPermissions();
365
366 mRestoredSettings = mSettings.readLP();
367 long startTime = SystemClock.uptimeMillis();
368
369 EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
370 startTime);
371
372 int scanMode = SCAN_MONITOR;
373
374 final HashSet<String> libFiles = new HashSet<String>();
375
376 mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
377
378 if (mInstaller != null) {
379 /**
380 * Out of paranoia, ensure that everything in the boot class
381 * path has been dexed.
382 */
383 String bootClassPath = System.getProperty("java.boot.class.path");
384 if (bootClassPath != null) {
385 String[] paths = splitString(bootClassPath, ':');
386 for (int i=0; i<paths.length; i++) {
387 try {
388 if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
389 libFiles.add(paths[i]);
390 mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
391 }
392 } catch (FileNotFoundException e) {
393 Log.w(TAG, "Boot class path not found: " + paths[i]);
394 } catch (IOException e) {
395 Log.w(TAG, "Exception reading boot class path: " + paths[i], e);
396 }
397 }
398 } else {
399 Log.w(TAG, "No BOOTCLASSPATH found!");
400 }
401
402 /**
403 * Also ensure all external libraries have had dexopt run on them.
404 */
405 if (mSharedLibraries.size() > 0) {
406 Iterator<String> libs = mSharedLibraries.values().iterator();
407 while (libs.hasNext()) {
408 String lib = libs.next();
409 try {
410 if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
411 libFiles.add(lib);
412 mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
413 }
414 } catch (FileNotFoundException e) {
415 Log.w(TAG, "Library not found: " + lib);
416 } catch (IOException e) {
417 Log.w(TAG, "Exception reading library: " + lib, e);
418 }
419 }
420 }
421
422 // Gross hack for now: we know this file doesn't contain any
423 // code, so don't dexopt it to avoid the resulting log spew.
424 libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
425
426 /**
427 * And there are a number of commands implemented in Java, which
428 * we currently need to do the dexopt on so that they can be
429 * run from a non-root shell.
430 */
431 String[] frameworkFiles = mFrameworkDir.list();
432 if (frameworkFiles != null && mInstaller != null) {
433 for (int i=0; i<frameworkFiles.length; i++) {
434 File libPath = new File(mFrameworkDir, frameworkFiles[i]);
435 String path = libPath.getPath();
436 // Skip the file if we alrady did it.
437 if (libFiles.contains(path)) {
438 continue;
439 }
440 // Skip the file if it is not a type we want to dexopt.
441 if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
442 continue;
443 }
444 try {
445 if (dalvik.system.DexFile.isDexOptNeeded(path)) {
446 mInstaller.dexopt(path, Process.SYSTEM_UID, true);
447 }
448 } catch (FileNotFoundException e) {
449 Log.w(TAG, "Jar not found: " + path);
450 } catch (IOException e) {
451 Log.w(TAG, "Exception reading jar: " + path, e);
452 }
453 }
454 }
455 }
456
457 mFrameworkInstallObserver = new AppDirObserver(
458 mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
459 mFrameworkInstallObserver.startWatching();
460 scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM,
461 scanMode | SCAN_NO_DEX);
462 mSystemAppDir = new File(Environment.getRootDirectory(), "app");
463 mSystemInstallObserver = new AppDirObserver(
464 mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
465 mSystemInstallObserver.startWatching();
466 scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);
467 mAppInstallDir = new File(dataDir, "app");
468 if (mInstaller == null) {
469 // Make sure these dirs exist, when we are running in
470 // the simulator.
471 mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists
472 }
473 //look for any incomplete package installations
474 ArrayList<String> deletePkgsList = mSettings.getListOfIncompleteInstallPackages();
475 //clean up list
476 for(int i = 0; i < deletePkgsList.size(); i++) {
477 //clean up here
478 cleanupInstallFailedPackage(deletePkgsList.get(i));
479 }
480 //delete tmp files
481 deleteTempPackageFiles();
482
483 EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_DATA_SCAN_START,
484 SystemClock.uptimeMillis());
485 mAppInstallObserver = new AppDirObserver(
486 mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
487 mAppInstallObserver.startWatching();
488 scanDirLI(mAppInstallDir, 0, scanMode);
489
490 mDrmAppInstallObserver = new AppDirObserver(
491 mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
492 mDrmAppInstallObserver.startWatching();
493 scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode);
494
495 EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_SCAN_END,
496 SystemClock.uptimeMillis());
497 Log.i(TAG, "Time to scan packages: "
498 + ((SystemClock.uptimeMillis()-startTime)/1000f)
499 + " seconds");
500
501 updatePermissionsLP();
502
503 mSettings.writeLP();
504
505 EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_READY,
506 SystemClock.uptimeMillis());
507
508 // Now after opening every single application zip, make sure they
509 // are all flushed. Not really needed, but keeps things nice and
510 // tidy.
511 Runtime.getRuntime().gc();
512 } // synchronized (mPackages)
513 } // synchronized (mInstallLock)
514 }
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 @Override
517 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
518 throws RemoteException {
519 try {
520 return super.onTransact(code, data, reply, flags);
521 } catch (RuntimeException e) {
522 if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) {
523 Log.e(TAG, "Package Manager Crash", e);
524 }
525 throw e;
526 }
527 }
528
529 void cleanupInstallFailedPackage(String packageName) {
530 if (mInstaller != null) {
531 int retCode = mInstaller.remove(packageName);
532 if (retCode < 0) {
533 Log.w(TAG, "Couldn't remove app data directory for package: "
534 + packageName + ", retcode=" + retCode);
535 }
536 } else {
537 //for emulator
538 PackageParser.Package pkg = mPackages.get(packageName);
539 File dataDir = new File(pkg.applicationInfo.dataDir);
540 dataDir.delete();
541 }
542 mSettings.removePackageLP(packageName);
543 }
544
545 void readPermissions() {
546 // Read permissions from .../etc/permission directory.
547 File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
548 if (!libraryDir.exists() || !libraryDir.isDirectory()) {
549 Log.w(TAG, "No directory " + libraryDir + ", skipping");
550 return;
551 }
552 if (!libraryDir.canRead()) {
553 Log.w(TAG, "Directory " + libraryDir + " cannot be read");
554 return;
555 }
556
557 // Iterate over the files in the directory and scan .xml files
558 for (File f : libraryDir.listFiles()) {
559 // We'll read platform.xml last
560 if (f.getPath().endsWith("etc/permissions/platform.xml")) {
561 continue;
562 }
563
564 if (!f.getPath().endsWith(".xml")) {
565 Log.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
566 continue;
567 }
568 if (!f.canRead()) {
569 Log.w(TAG, "Permissions library file " + f + " cannot be read");
570 continue;
571 }
572
573 readPermissionsFromXml(f);
574 }
575
576 // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
577 final File permFile = new File(Environment.getRootDirectory(),
578 "etc/permissions/platform.xml");
579 readPermissionsFromXml(permFile);
580 }
581
582 private void readPermissionsFromXml(File permFile) {
583 FileReader permReader = null;
584 try {
585 permReader = new FileReader(permFile);
586 } catch (FileNotFoundException e) {
587 Log.w(TAG, "Couldn't find or open permissions file " + permFile);
588 return;
589 }
590
591 try {
592 XmlPullParser parser = Xml.newPullParser();
593 parser.setInput(permReader);
594
595 XmlUtils.beginDocument(parser, "permissions");
596
597 while (true) {
598 XmlUtils.nextElement(parser);
599 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
600 break;
601 }
602
603 String name = parser.getName();
604 if ("group".equals(name)) {
605 String gidStr = parser.getAttributeValue(null, "gid");
606 if (gidStr != null) {
607 int gid = Integer.parseInt(gidStr);
608 mGlobalGids = appendInt(mGlobalGids, gid);
609 } else {
610 Log.w(TAG, "<group> without gid at "
611 + parser.getPositionDescription());
612 }
613
614 XmlUtils.skipCurrentTag(parser);
615 continue;
616 } else if ("permission".equals(name)) {
617 String perm = parser.getAttributeValue(null, "name");
618 if (perm == null) {
619 Log.w(TAG, "<permission> without name at "
620 + parser.getPositionDescription());
621 XmlUtils.skipCurrentTag(parser);
622 continue;
623 }
624 perm = perm.intern();
625 readPermission(parser, perm);
626
627 } else if ("assign-permission".equals(name)) {
628 String perm = parser.getAttributeValue(null, "name");
629 if (perm == null) {
630 Log.w(TAG, "<assign-permission> without name at "
631 + parser.getPositionDescription());
632 XmlUtils.skipCurrentTag(parser);
633 continue;
634 }
635 String uidStr = parser.getAttributeValue(null, "uid");
636 if (uidStr == null) {
637 Log.w(TAG, "<assign-permission> without uid at "
638 + parser.getPositionDescription());
639 XmlUtils.skipCurrentTag(parser);
640 continue;
641 }
642 int uid = Process.getUidForName(uidStr);
643 if (uid < 0) {
644 Log.w(TAG, "<assign-permission> with unknown uid \""
645 + uidStr + "\" at "
646 + parser.getPositionDescription());
647 XmlUtils.skipCurrentTag(parser);
648 continue;
649 }
650 perm = perm.intern();
651 HashSet<String> perms = mSystemPermissions.get(uid);
652 if (perms == null) {
653 perms = new HashSet<String>();
654 mSystemPermissions.put(uid, perms);
655 }
656 perms.add(perm);
657 XmlUtils.skipCurrentTag(parser);
658
659 } else if ("library".equals(name)) {
660 String lname = parser.getAttributeValue(null, "name");
661 String lfile = parser.getAttributeValue(null, "file");
662 if (lname == null) {
663 Log.w(TAG, "<library> without name at "
664 + parser.getPositionDescription());
665 } else if (lfile == null) {
666 Log.w(TAG, "<library> without file at "
667 + parser.getPositionDescription());
668 } else {
669 Log.i(TAG, "Got library " + lname + " in " + lfile);
670 this.mSharedLibraries.put(lname, lfile);
671 }
672 XmlUtils.skipCurrentTag(parser);
673 continue;
674
675 } else {
676 XmlUtils.skipCurrentTag(parser);
677 continue;
678 }
679
680 }
681 } catch (XmlPullParserException e) {
682 Log.w(TAG, "Got execption parsing permissions.", e);
683 } catch (IOException e) {
684 Log.w(TAG, "Got execption parsing permissions.", e);
685 }
686 }
687
688 void readPermission(XmlPullParser parser, String name)
689 throws IOException, XmlPullParserException {
690
691 name = name.intern();
692
693 BasePermission bp = mSettings.mPermissions.get(name);
694 if (bp == null) {
695 bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);
696 mSettings.mPermissions.put(name, bp);
697 }
698 int outerDepth = parser.getDepth();
699 int type;
700 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
701 && (type != XmlPullParser.END_TAG
702 || parser.getDepth() > outerDepth)) {
703 if (type == XmlPullParser.END_TAG
704 || type == XmlPullParser.TEXT) {
705 continue;
706 }
707
708 String tagName = parser.getName();
709 if ("group".equals(tagName)) {
710 String gidStr = parser.getAttributeValue(null, "gid");
711 if (gidStr != null) {
712 int gid = Process.getGidForName(gidStr);
713 bp.gids = appendInt(bp.gids, gid);
714 } else {
715 Log.w(TAG, "<group> without gid at "
716 + parser.getPositionDescription());
717 }
718 }
719 XmlUtils.skipCurrentTag(parser);
720 }
721 }
722
723 static int[] appendInt(int[] cur, int val) {
724 if (cur == null) {
725 return new int[] { val };
726 }
727 final int N = cur.length;
728 for (int i=0; i<N; i++) {
729 if (cur[i] == val) {
730 return cur;
731 }
732 }
733 int[] ret = new int[N+1];
734 System.arraycopy(cur, 0, ret, 0, N);
735 ret[N] = val;
736 return ret;
737 }
738
739 static int[] appendInts(int[] cur, int[] add) {
740 if (add == null) return cur;
741 if (cur == null) return add;
742 final int N = add.length;
743 for (int i=0; i<N; i++) {
744 cur = appendInt(cur, add[i]);
745 }
746 return cur;
747 }
748
749 PackageInfo generatePackageInfo(PackageParser.Package p, int flags) {
750 final PackageSetting ps = (PackageSetting)p.mExtras;
751 if (ps == null) {
752 return null;
753 }
754 final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
755 return PackageParser.generatePackageInfo(p, gp.gids, flags);
756 }
757
758 public PackageInfo getPackageInfo(String packageName, int flags) {
759 synchronized (mPackages) {
760 PackageParser.Package p = mPackages.get(packageName);
761 if (Config.LOGV) Log.v(
762 TAG, "getApplicationInfo " + packageName
763 + ": " + p);
764 if (p != null) {
765 return generatePackageInfo(p, flags);
766 }
767 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
768 return generatePackageInfoFromSettingsLP(packageName, flags);
769 }
770 }
771 return null;
772 }
773
774 public int getPackageUid(String packageName) {
775 synchronized (mPackages) {
776 PackageParser.Package p = mPackages.get(packageName);
777 if(p != null) {
778 return p.applicationInfo.uid;
779 }
780 PackageSetting ps = mSettings.mPackages.get(packageName);
781 if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) {
782 return -1;
783 }
784 p = ps.pkg;
785 return p != null ? p.applicationInfo.uid : -1;
786 }
787 }
788
789 public int[] getPackageGids(String packageName) {
790 synchronized (mPackages) {
791 PackageParser.Package p = mPackages.get(packageName);
792 if (Config.LOGV) Log.v(
793 TAG, "getApplicationInfo " + packageName
794 + ": " + p);
795 if (p != null) {
796 final PackageSetting ps = (PackageSetting)p.mExtras;
797 final SharedUserSetting suid = ps.sharedUser;
798 return suid != null ? suid.gids : ps.gids;
799 }
800 }
801 // stupid thing to indicate an error.
802 return new int[0];
803 }
804
805 public PermissionInfo getPermissionInfo(String name, int flags) {
806 synchronized (mPackages) {
807 final BasePermission p = mSettings.mPermissions.get(name);
808 if (p != null && p.perm != null) {
809 return PackageParser.generatePermissionInfo(p.perm, flags);
810 }
811 return null;
812 }
813 }
814
815 public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
816 synchronized (mPackages) {
817 ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
818 for (BasePermission p : mSettings.mPermissions.values()) {
819 if (group == null) {
820 if (p.perm.info.group == null) {
821 out.add(PackageParser.generatePermissionInfo(p.perm, flags));
822 }
823 } else {
824 if (group.equals(p.perm.info.group)) {
825 out.add(PackageParser.generatePermissionInfo(p.perm, flags));
826 }
827 }
828 }
829
830 if (out.size() > 0) {
831 return out;
832 }
833 return mPermissionGroups.containsKey(group) ? out : null;
834 }
835 }
836
837 public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
838 synchronized (mPackages) {
839 return PackageParser.generatePermissionGroupInfo(
840 mPermissionGroups.get(name), flags);
841 }
842 }
843
844 public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
845 synchronized (mPackages) {
846 final int N = mPermissionGroups.size();
847 ArrayList<PermissionGroupInfo> out
848 = new ArrayList<PermissionGroupInfo>(N);
849 for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) {
850 out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
851 }
852 return out;
853 }
854 }
855
856 private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) {
857 PackageSetting ps = mSettings.mPackages.get(packageName);
858 if(ps != null) {
859 if(ps.pkg == null) {
860 PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags);
861 if(pInfo != null) {
862 return pInfo.applicationInfo;
863 }
864 return null;
865 }
866 return PackageParser.generateApplicationInfo(ps.pkg, flags);
867 }
868 return null;
869 }
870
871 private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) {
872 PackageSetting ps = mSettings.mPackages.get(packageName);
873 if(ps != null) {
874 if(ps.pkg == null) {
875 ps.pkg = new PackageParser.Package(packageName);
876 ps.pkg.applicationInfo.packageName = packageName;
877 }
878 return generatePackageInfo(ps.pkg, flags);
879 }
880 return null;
881 }
882
883 public ApplicationInfo getApplicationInfo(String packageName, int flags) {
884 synchronized (mPackages) {
885 PackageParser.Package p = mPackages.get(packageName);
886 if (Config.LOGV) Log.v(
887 TAG, "getApplicationInfo " + packageName
888 + ": " + p);
889 if (p != null) {
890 // Note: isEnabledLP() does not apply here - always return info
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700891 ApplicationInfo appInfo = PackageParser.generateApplicationInfo(p, flags);
892 if (!mCompatibilityModeEnabled) {
893 appInfo.disableCompatibilityMode();
894 }
895 return appInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 }
897 if ("android".equals(packageName)||"system".equals(packageName)) {
898 return mAndroidApplication;
899 }
900 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
901 return generateApplicationInfoFromSettingsLP(packageName, flags);
902 }
903 }
904 return null;
905 }
906
907
908 public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) {
909 mContext.enforceCallingOrSelfPermission(
910 android.Manifest.permission.CLEAR_APP_CACHE, null);
911 // Queue up an async operation since clearing cache may take a little while.
912 mHandler.post(new Runnable() {
913 public void run() {
914 mHandler.removeCallbacks(this);
915 int retCode = -1;
916 if (mInstaller != null) {
917 retCode = mInstaller.freeCache(freeStorageSize);
918 if (retCode < 0) {
919 Log.w(TAG, "Couldn't clear application caches");
920 }
921 } //end if mInstaller
922 if (observer != null) {
923 try {
924 observer.onRemoveCompleted(null, (retCode >= 0));
925 } catch (RemoteException e) {
926 Log.w(TAG, "RemoveException when invoking call back");
927 }
928 }
929 }
930 });
931 }
932
933 public void freeStorage(final long freeStorageSize, final PendingIntent opFinishedIntent) {
934 mContext.enforceCallingOrSelfPermission(
935 android.Manifest.permission.CLEAR_APP_CACHE, null);
936 // Queue up an async operation since clearing cache may take a little while.
937 mHandler.post(new Runnable() {
938 public void run() {
939 mHandler.removeCallbacks(this);
940 int retCode = -1;
941 if (mInstaller != null) {
942 retCode = mInstaller.freeCache(freeStorageSize);
943 if (retCode < 0) {
944 Log.w(TAG, "Couldn't clear application caches");
945 }
946 }
947 if(opFinishedIntent != null) {
948 try {
949 // Callback via pending intent
950 opFinishedIntent.send((retCode >= 0) ? 1 : 0);
951 } catch (CanceledException e1) {
952 Log.i(TAG, "Failed to send pending intent");
953 }
954 }
955 }
956 });
957 }
958
959 public ActivityInfo getActivityInfo(ComponentName component, int flags) {
960 synchronized (mPackages) {
961 PackageParser.Activity a = mActivities.mActivities.get(component);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700962
963 if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 if (a != null && mSettings.isEnabledLP(a.info, flags)) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700965 ActivityInfo ainfo = PackageParser.generateActivityInfo(a, flags);
966 if (ainfo != null && (flags & PackageManager.GET_EXPANDABLE) != 0) {
967 ApplicationInfo appInfo = getApplicationInfo(component.getPackageName(),
968 PackageManager.GET_EXPANDABLE | PackageManager.GET_SUPPORTS_DENSITIES);
969 if (appInfo != null && !appInfo.expandable) {
970 // Check if the screen size is same as what the application expect.
971 CompatibilityInfo info = new CompatibilityInfo(appInfo);
972 DisplayMetrics metrics = new DisplayMetrics();
973 metrics.setTo(mMetrics);
974 int orientation = mMetrics.widthPixels > mMetrics.heightPixels ?
975 Configuration.ORIENTATION_LANDSCAPE :
976 Configuration.ORIENTATION_PORTRAIT;
977 metrics.updateMetrics(info, orientation);
978 if (!info.mExpandable) {
979 // Don't allow an app that cannot expand to handle rotation.
980 ainfo.configChanges &= ~ ActivityInfo.CONFIG_ORIENTATION;
981 } else {
982 appInfo.expandable = true;
983 }
984 if (DEBUG_SETTINGS) {
985 Log.d(TAG, "component=" + component +
986 ", expandable:" + appInfo.expandable);
987 }
988 }
989 }
990 return ainfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 }
992 if (mResolveComponentName.equals(component)) {
993 return mResolveActivity;
994 }
995 }
996 return null;
997 }
998
999 public ActivityInfo getReceiverInfo(ComponentName component, int flags) {
1000 synchronized (mPackages) {
1001 PackageParser.Activity a = mReceivers.mActivities.get(component);
1002 if (Config.LOGV) Log.v(
1003 TAG, "getReceiverInfo " + component + ": " + a);
1004 if (a != null && mSettings.isEnabledLP(a.info, flags)) {
1005 return PackageParser.generateActivityInfo(a, flags);
1006 }
1007 }
1008 return null;
1009 }
1010
1011 public ServiceInfo getServiceInfo(ComponentName component, int flags) {
1012 synchronized (mPackages) {
1013 PackageParser.Service s = mServices.mServices.get(component);
1014 if (Config.LOGV) Log.v(
1015 TAG, "getServiceInfo " + component + ": " + s);
1016 if (s != null && mSettings.isEnabledLP(s.info, flags)) {
1017 return PackageParser.generateServiceInfo(s, flags);
1018 }
1019 }
1020 return null;
1021 }
1022
1023 public String[] getSystemSharedLibraryNames() {
1024 Set<String> libSet;
1025 synchronized (mPackages) {
1026 libSet = mSharedLibraries.keySet();
1027 }
1028 int size = libSet.size();
1029 if (size > 0) {
1030 String[] libs = new String[size];
1031 libSet.toArray(libs);
1032 return libs;
1033 }
1034 return null;
1035 }
1036
1037 public int checkPermission(String permName, String pkgName) {
1038 synchronized (mPackages) {
1039 PackageParser.Package p = mPackages.get(pkgName);
1040 if (p != null && p.mExtras != null) {
1041 PackageSetting ps = (PackageSetting)p.mExtras;
1042 if (ps.sharedUser != null) {
1043 if (ps.sharedUser.grantedPermissions.contains(permName)) {
1044 return PackageManager.PERMISSION_GRANTED;
1045 }
1046 } else if (ps.grantedPermissions.contains(permName)) {
1047 return PackageManager.PERMISSION_GRANTED;
1048 }
1049 }
1050 }
1051 return PackageManager.PERMISSION_DENIED;
1052 }
1053
1054 public int checkUidPermission(String permName, int uid) {
1055 synchronized (mPackages) {
1056 Object obj = mSettings.getUserIdLP(uid);
1057 if (obj != null) {
1058 if (obj instanceof SharedUserSetting) {
1059 SharedUserSetting sus = (SharedUserSetting)obj;
1060 if (sus.grantedPermissions.contains(permName)) {
1061 return PackageManager.PERMISSION_GRANTED;
1062 }
1063 } else if (obj instanceof PackageSetting) {
1064 PackageSetting ps = (PackageSetting)obj;
1065 if (ps.grantedPermissions.contains(permName)) {
1066 return PackageManager.PERMISSION_GRANTED;
1067 }
1068 }
1069 } else {
1070 HashSet<String> perms = mSystemPermissions.get(uid);
1071 if (perms != null && perms.contains(permName)) {
1072 return PackageManager.PERMISSION_GRANTED;
1073 }
1074 }
1075 }
1076 return PackageManager.PERMISSION_DENIED;
1077 }
1078
1079 private BasePermission findPermissionTreeLP(String permName) {
1080 for(BasePermission bp : mSettings.mPermissionTrees.values()) {
1081 if (permName.startsWith(bp.name) &&
1082 permName.length() > bp.name.length() &&
1083 permName.charAt(bp.name.length()) == '.') {
1084 return bp;
1085 }
1086 }
1087 return null;
1088 }
1089
1090 private BasePermission checkPermissionTreeLP(String permName) {
1091 if (permName != null) {
1092 BasePermission bp = findPermissionTreeLP(permName);
1093 if (bp != null) {
1094 if (bp.uid == Binder.getCallingUid()) {
1095 return bp;
1096 }
1097 throw new SecurityException("Calling uid "
1098 + Binder.getCallingUid()
1099 + " is not allowed to add to permission tree "
1100 + bp.name + " owned by uid " + bp.uid);
1101 }
1102 }
1103 throw new SecurityException("No permission tree found for " + permName);
1104 }
1105
1106 public boolean addPermission(PermissionInfo info) {
1107 synchronized (mPackages) {
1108 if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
1109 throw new SecurityException("Label must be specified in permission");
1110 }
1111 BasePermission tree = checkPermissionTreeLP(info.name);
1112 BasePermission bp = mSettings.mPermissions.get(info.name);
1113 boolean added = bp == null;
1114 if (added) {
1115 bp = new BasePermission(info.name, tree.sourcePackage,
1116 BasePermission.TYPE_DYNAMIC);
1117 } else if (bp.type != BasePermission.TYPE_DYNAMIC) {
1118 throw new SecurityException(
1119 "Not allowed to modify non-dynamic permission "
1120 + info.name);
1121 }
1122 bp.perm = new PackageParser.Permission(tree.perm.owner,
1123 new PermissionInfo(info));
1124 bp.perm.info.packageName = tree.perm.info.packageName;
1125 bp.uid = tree.uid;
1126 if (added) {
1127 mSettings.mPermissions.put(info.name, bp);
1128 }
1129 mSettings.writeLP();
1130 return added;
1131 }
1132 }
1133
1134 public void removePermission(String name) {
1135 synchronized (mPackages) {
1136 checkPermissionTreeLP(name);
1137 BasePermission bp = mSettings.mPermissions.get(name);
1138 if (bp != null) {
1139 if (bp.type != BasePermission.TYPE_DYNAMIC) {
1140 throw new SecurityException(
1141 "Not allowed to modify non-dynamic permission "
1142 + name);
1143 }
1144 mSettings.mPermissions.remove(name);
1145 mSettings.writeLP();
1146 }
1147 }
1148 }
1149
1150 public int checkSignatures(String pkg1, String pkg2) {
1151 synchronized (mPackages) {
1152 PackageParser.Package p1 = mPackages.get(pkg1);
1153 PackageParser.Package p2 = mPackages.get(pkg2);
1154 if (p1 == null || p1.mExtras == null
1155 || p2 == null || p2.mExtras == null) {
1156 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
1157 }
1158 return checkSignaturesLP(p1, p2);
1159 }
1160 }
1161
1162 int checkSignaturesLP(PackageParser.Package p1, PackageParser.Package p2) {
1163 if (p1.mSignatures == null) {
1164 return p2.mSignatures == null
1165 ? PackageManager.SIGNATURE_NEITHER_SIGNED
1166 : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
1167 }
1168 if (p2.mSignatures == null) {
1169 return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
1170 }
1171 final int N1 = p1.mSignatures.length;
1172 final int N2 = p2.mSignatures.length;
1173 for (int i=0; i<N1; i++) {
1174 boolean match = false;
1175 for (int j=0; j<N2; j++) {
1176 if (p1.mSignatures[i].equals(p2.mSignatures[j])) {
1177 match = true;
1178 break;
1179 }
1180 }
1181 if (!match) {
1182 return PackageManager.SIGNATURE_NO_MATCH;
1183 }
1184 }
1185 return PackageManager.SIGNATURE_MATCH;
1186 }
1187
1188 public String[] getPackagesForUid(int uid) {
1189 synchronized (mPackages) {
1190 Object obj = mSettings.getUserIdLP(uid);
1191 if (obj instanceof SharedUserSetting) {
1192 SharedUserSetting sus = (SharedUserSetting)obj;
1193 final int N = sus.packages.size();
1194 String[] res = new String[N];
1195 Iterator<PackageSetting> it = sus.packages.iterator();
1196 int i=0;
1197 while (it.hasNext()) {
1198 res[i++] = it.next().name;
1199 }
1200 return res;
1201 } else if (obj instanceof PackageSetting) {
1202 PackageSetting ps = (PackageSetting)obj;
1203 return new String[] { ps.name };
1204 }
1205 }
1206 return null;
1207 }
1208
1209 public String getNameForUid(int uid) {
1210 synchronized (mPackages) {
1211 Object obj = mSettings.getUserIdLP(uid);
1212 if (obj instanceof SharedUserSetting) {
1213 SharedUserSetting sus = (SharedUserSetting)obj;
1214 return sus.name + ":" + sus.userId;
1215 } else if (obj instanceof PackageSetting) {
1216 PackageSetting ps = (PackageSetting)obj;
1217 return ps.name;
1218 }
1219 }
1220 return null;
1221 }
1222
1223 public int getUidForSharedUser(String sharedUserName) {
1224 if(sharedUserName == null) {
1225 return -1;
1226 }
1227 synchronized (mPackages) {
1228 SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false);
1229 if(suid == null) {
1230 return -1;
1231 }
1232 return suid.userId;
1233 }
1234 }
1235
1236 public ResolveInfo resolveIntent(Intent intent, String resolvedType,
1237 int flags) {
1238 List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags);
Mihai Predaeae850c2009-05-13 10:13:48 +02001239 return chooseBestActivity(intent, resolvedType, flags, query);
1240 }
1241
1242 public ResolveInfo resolveIntentForPackage(Intent intent, String resolvedType,
1243 int flags, String packageName) {
1244 ComponentName comp = intent.getComponent();
1245 if (comp != null) {
1246 // if this is an explicit intent, it must have the same the packageName
1247 if (packageName.equals(comp.getPackageName())) {
1248 return resolveIntent(intent, resolvedType, flags);
1249 }
1250 return null;
1251 } else {
1252 List<ResolveInfo> query = null;
1253 synchronized (mPackages) {
1254 PackageParser.Package pkg = mPackages.get(packageName);
1255 if (pkg != null) {
1256 query = (List<ResolveInfo>) mActivities.
1257 queryIntentForPackage(intent, resolvedType, flags, pkg.activities);
1258 }
1259 }
1260 return chooseBestActivity(intent, resolvedType, flags, query);
1261 }
1262 }
1263
1264 private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
1265 int flags, List<ResolveInfo> query) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 if (query != null) {
1267 final int N = query.size();
1268 if (N == 1) {
1269 return query.get(0);
1270 } else if (N > 1) {
1271 // If there is more than one activity with the same priority,
1272 // then let the user decide between them.
1273 ResolveInfo r0 = query.get(0);
1274 ResolveInfo r1 = query.get(1);
1275 if (false) {
1276 System.out.println(r0.activityInfo.name +
1277 "=" + r0.priority + " vs " +
1278 r1.activityInfo.name +
1279 "=" + r1.priority);
1280 }
1281 // If the first activity has a higher priority, or a different
1282 // default, then it is always desireable to pick it.
1283 if (r0.priority != r1.priority
1284 || r0.preferredOrder != r1.preferredOrder
1285 || r0.isDefault != r1.isDefault) {
1286 return query.get(0);
1287 }
1288 // If we have saved a preference for a preferred activity for
1289 // this Intent, use that.
1290 ResolveInfo ri = findPreferredActivity(intent, resolvedType,
1291 flags, query, r0.priority);
1292 if (ri != null) {
1293 return ri;
1294 }
1295 return mResolveInfo;
1296 }
1297 }
1298 return null;
1299 }
1300
1301 ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
1302 int flags, List<ResolveInfo> query, int priority) {
1303 synchronized (mPackages) {
1304 if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
1305 List<PreferredActivity> prefs =
Mihai Preda074edef2009-05-18 17:13:31 +02001306 mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
1308 if (prefs != null && prefs.size() > 0) {
1309 // First figure out how good the original match set is.
1310 // We will only allow preferred activities that came
1311 // from the same match quality.
1312 int match = 0;
1313 final int N = query.size();
1314 if (DEBUG_PREFERRED) Log.v(TAG, "Figuring out best match...");
1315 for (int j=0; j<N; j++) {
1316 ResolveInfo ri = query.get(j);
1317 if (DEBUG_PREFERRED) Log.v(TAG, "Match for " + ri.activityInfo
1318 + ": 0x" + Integer.toHexString(match));
1319 if (ri.match > match) match = ri.match;
1320 }
1321 if (DEBUG_PREFERRED) Log.v(TAG, "Best match: 0x"
1322 + Integer.toHexString(match));
1323 match &= IntentFilter.MATCH_CATEGORY_MASK;
1324 final int M = prefs.size();
1325 for (int i=0; i<M; i++) {
1326 PreferredActivity pa = prefs.get(i);
1327 if (pa.mMatch != match) {
1328 continue;
1329 }
1330 ActivityInfo ai = getActivityInfo(pa.mActivity, flags);
1331 if (DEBUG_PREFERRED) {
1332 Log.v(TAG, "Got preferred activity:");
1333 ai.dump(new LogPrinter(Log.INFO, TAG), " ");
1334 }
1335 if (ai != null) {
1336 for (int j=0; j<N; j++) {
1337 ResolveInfo ri = query.get(j);
1338 if (!ri.activityInfo.applicationInfo.packageName
1339 .equals(ai.applicationInfo.packageName)) {
1340 continue;
1341 }
1342 if (!ri.activityInfo.name.equals(ai.name)) {
1343 continue;
1344 }
1345
1346 // Okay we found a previously set preferred app.
1347 // If the result set is different from when this
1348 // was created, we need to clear it and re-ask the
1349 // user their preference.
1350 if (!pa.sameSet(query, priority)) {
1351 Log.i(TAG, "Result set changed, dropping preferred activity for "
1352 + intent + " type " + resolvedType);
1353 mSettings.mPreferredActivities.removeFilter(pa);
1354 return null;
1355 }
1356
1357 // Yay!
1358 return ri;
1359 }
1360 }
1361 }
1362 }
1363 }
1364 return null;
1365 }
1366
1367 public List<ResolveInfo> queryIntentActivities(Intent intent,
1368 String resolvedType, int flags) {
1369 ComponentName comp = intent.getComponent();
1370 if (comp != null) {
1371 List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
1372 ActivityInfo ai = getActivityInfo(comp, flags);
1373 if (ai != null) {
1374 ResolveInfo ri = new ResolveInfo();
1375 ri.activityInfo = ai;
1376 list.add(ri);
1377 }
1378 return list;
1379 }
1380
1381 synchronized (mPackages) {
1382 return (List<ResolveInfo>)mActivities.
Mihai Preda074edef2009-05-18 17:13:31 +02001383 queryIntent(intent, resolvedType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
1385 }
1386
1387 public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
1388 Intent[] specifics, String[] specificTypes, Intent intent,
1389 String resolvedType, int flags) {
1390 final String resultsAction = intent.getAction();
1391
1392 List<ResolveInfo> results = queryIntentActivities(
1393 intent, resolvedType, flags|PackageManager.GET_RESOLVED_FILTER);
1394 if (Config.LOGV) Log.v(TAG, "Query " + intent + ": " + results);
1395
1396 int specificsPos = 0;
1397 int N;
1398
1399 // todo: note that the algorithm used here is O(N^2). This
1400 // isn't a problem in our current environment, but if we start running
1401 // into situations where we have more than 5 or 10 matches then this
1402 // should probably be changed to something smarter...
1403
1404 // First we go through and resolve each of the specific items
1405 // that were supplied, taking care of removing any corresponding
1406 // duplicate items in the generic resolve list.
1407 if (specifics != null) {
1408 for (int i=0; i<specifics.length; i++) {
1409 final Intent sintent = specifics[i];
1410 if (sintent == null) {
1411 continue;
1412 }
1413
1414 if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + sintent);
1415 String action = sintent.getAction();
1416 if (resultsAction != null && resultsAction.equals(action)) {
1417 // If this action was explicitly requested, then don't
1418 // remove things that have it.
1419 action = null;
1420 }
1421 ComponentName comp = sintent.getComponent();
1422 ResolveInfo ri = null;
1423 ActivityInfo ai = null;
1424 if (comp == null) {
1425 ri = resolveIntent(
1426 sintent,
1427 specificTypes != null ? specificTypes[i] : null,
1428 flags);
1429 if (ri == null) {
1430 continue;
1431 }
1432 if (ri == mResolveInfo) {
1433 // ACK! Must do something better with this.
1434 }
1435 ai = ri.activityInfo;
1436 comp = new ComponentName(ai.applicationInfo.packageName,
1437 ai.name);
1438 } else {
1439 ai = getActivityInfo(comp, flags);
1440 if (ai == null) {
1441 continue;
1442 }
1443 }
1444
1445 // Look for any generic query activities that are duplicates
1446 // of this specific one, and remove them from the results.
1447 if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + ai);
1448 N = results.size();
1449 int j;
1450 for (j=specificsPos; j<N; j++) {
1451 ResolveInfo sri = results.get(j);
1452 if ((sri.activityInfo.name.equals(comp.getClassName())
1453 && sri.activityInfo.applicationInfo.packageName.equals(
1454 comp.getPackageName()))
1455 || (action != null && sri.filter.matchAction(action))) {
1456 results.remove(j);
1457 if (Config.LOGV) Log.v(
1458 TAG, "Removing duplicate item from " + j
1459 + " due to specific " + specificsPos);
1460 if (ri == null) {
1461 ri = sri;
1462 }
1463 j--;
1464 N--;
1465 }
1466 }
1467
1468 // Add this specific item to its proper place.
1469 if (ri == null) {
1470 ri = new ResolveInfo();
1471 ri.activityInfo = ai;
1472 }
1473 results.add(specificsPos, ri);
1474 ri.specificIndex = i;
1475 specificsPos++;
1476 }
1477 }
1478
1479 // Now we go through the remaining generic results and remove any
1480 // duplicate actions that are found here.
1481 N = results.size();
1482 for (int i=specificsPos; i<N-1; i++) {
1483 final ResolveInfo rii = results.get(i);
1484 if (rii.filter == null) {
1485 continue;
1486 }
1487
1488 // Iterate over all of the actions of this result's intent
1489 // filter... typically this should be just one.
1490 final Iterator<String> it = rii.filter.actionsIterator();
1491 if (it == null) {
1492 continue;
1493 }
1494 while (it.hasNext()) {
1495 final String action = it.next();
1496 if (resultsAction != null && resultsAction.equals(action)) {
1497 // If this action was explicitly requested, then don't
1498 // remove things that have it.
1499 continue;
1500 }
1501 for (int j=i+1; j<N; j++) {
1502 final ResolveInfo rij = results.get(j);
1503 if (rij.filter != null && rij.filter.hasAction(action)) {
1504 results.remove(j);
1505 if (Config.LOGV) Log.v(
1506 TAG, "Removing duplicate item from " + j
1507 + " due to action " + action + " at " + i);
1508 j--;
1509 N--;
1510 }
1511 }
1512 }
1513
1514 // If the caller didn't request filter information, drop it now
1515 // so we don't have to marshall/unmarshall it.
1516 if ((flags&PackageManager.GET_RESOLVED_FILTER) == 0) {
1517 rii.filter = null;
1518 }
1519 }
1520
1521 // Filter out the caller activity if so requested.
1522 if (caller != null) {
1523 N = results.size();
1524 for (int i=0; i<N; i++) {
1525 ActivityInfo ainfo = results.get(i).activityInfo;
1526 if (caller.getPackageName().equals(ainfo.applicationInfo.packageName)
1527 && caller.getClassName().equals(ainfo.name)) {
1528 results.remove(i);
1529 break;
1530 }
1531 }
1532 }
1533
1534 // If the caller didn't request filter information,
1535 // drop them now so we don't have to
1536 // marshall/unmarshall it.
1537 if ((flags&PackageManager.GET_RESOLVED_FILTER) == 0) {
1538 N = results.size();
1539 for (int i=0; i<N; i++) {
1540 results.get(i).filter = null;
1541 }
1542 }
1543
1544 if (Config.LOGV) Log.v(TAG, "Result: " + results);
1545 return results;
1546 }
1547
1548 public List<ResolveInfo> queryIntentReceivers(Intent intent,
1549 String resolvedType, int flags) {
1550 synchronized (mPackages) {
1551 return (List<ResolveInfo>)mReceivers.
Mihai Preda074edef2009-05-18 17:13:31 +02001552 queryIntent(intent, resolvedType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 }
1554 }
1555
1556 public ResolveInfo resolveService(Intent intent, String resolvedType,
1557 int flags) {
1558 List<ResolveInfo> query = queryIntentServices(intent, resolvedType,
1559 flags);
1560 if (query != null) {
1561 if (query.size() >= 1) {
1562 // If there is more than one service with the same priority,
1563 // just arbitrarily pick the first one.
1564 return query.get(0);
1565 }
1566 }
1567 return null;
1568 }
1569
1570 public List<ResolveInfo> queryIntentServices(Intent intent,
1571 String resolvedType, int flags) {
1572 ComponentName comp = intent.getComponent();
1573 if (comp != null) {
1574 List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
1575 ServiceInfo si = getServiceInfo(comp, flags);
1576 if (si != null) {
1577 ResolveInfo ri = new ResolveInfo();
1578 ri.serviceInfo = si;
1579 list.add(ri);
1580 }
1581 return list;
1582 }
1583
1584 synchronized (mPackages) {
Mihai Preda074edef2009-05-18 17:13:31 +02001585 return (List<ResolveInfo>)mServices.queryIntent(intent, resolvedType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 }
1587 }
1588
1589 public List<PackageInfo> getInstalledPackages(int flags) {
1590 ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
1591
1592 synchronized (mPackages) {
1593 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1594 Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
1595 while (i.hasNext()) {
1596 final PackageSetting ps = i.next();
1597 PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags);
1598 if(psPkg != null) {
1599 finalList.add(psPkg);
1600 }
1601 }
1602 }
1603 else {
1604 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1605 while (i.hasNext()) {
1606 final PackageParser.Package p = i.next();
1607 if (p.applicationInfo != null) {
1608 PackageInfo pi = generatePackageInfo(p, flags);
1609 if(pi != null) {
1610 finalList.add(pi);
1611 }
1612 }
1613 }
1614 }
1615 }
1616 return finalList;
1617 }
1618
1619 public List<ApplicationInfo> getInstalledApplications(int flags) {
1620 ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
1621 synchronized(mPackages) {
1622 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1623 Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
1624 while (i.hasNext()) {
1625 final PackageSetting ps = i.next();
1626 ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags);
1627 if(ai != null) {
1628 finalList.add(ai);
1629 }
1630 }
1631 }
1632 else {
1633 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1634 while (i.hasNext()) {
1635 final PackageParser.Package p = i.next();
1636 if (p.applicationInfo != null) {
1637 ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags);
1638 if(ai != null) {
1639 finalList.add(ai);
1640 }
1641 }
1642 }
1643 }
1644 }
1645 return finalList;
1646 }
1647
1648 public List<ApplicationInfo> getPersistentApplications(int flags) {
1649 ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
1650
1651 synchronized (mPackages) {
1652 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1653 while (i.hasNext()) {
1654 PackageParser.Package p = i.next();
1655 if (p.applicationInfo != null
1656 && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
1657 && (!mSafeMode || (p.applicationInfo.flags
1658 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
1659 finalList.add(p.applicationInfo);
1660 }
1661 }
1662 }
1663
1664 return finalList;
1665 }
1666
1667 public ProviderInfo resolveContentProvider(String name, int flags) {
1668 synchronized (mPackages) {
1669 final PackageParser.Provider provider = mProviders.get(name);
1670 return provider != null
1671 && mSettings.isEnabledLP(provider.info, flags)
1672 && (!mSafeMode || (provider.info.applicationInfo.flags
1673 &ApplicationInfo.FLAG_SYSTEM) != 0)
1674 ? PackageParser.generateProviderInfo(provider, flags)
1675 : null;
1676 }
1677 }
1678
1679 public void querySyncProviders(List outNames, List outInfo) {
1680 synchronized (mPackages) {
1681 Iterator<Map.Entry<String, PackageParser.Provider>> i
1682 = mProviders.entrySet().iterator();
1683
1684 while (i.hasNext()) {
1685 Map.Entry<String, PackageParser.Provider> entry = i.next();
1686 PackageParser.Provider p = entry.getValue();
1687
1688 if (p.syncable
1689 && (!mSafeMode || (p.info.applicationInfo.flags
1690 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
1691 outNames.add(entry.getKey());
1692 outInfo.add(PackageParser.generateProviderInfo(p, 0));
1693 }
1694 }
1695 }
1696 }
1697
1698 public List<ProviderInfo> queryContentProviders(String processName,
1699 int uid, int flags) {
1700 ArrayList<ProviderInfo> finalList = null;
1701
1702 synchronized (mPackages) {
1703 Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
1704 while (i.hasNext()) {
1705 PackageParser.Provider p = i.next();
1706 if (p.info.authority != null
1707 && (processName == null ||
1708 (p.info.processName.equals(processName)
1709 && p.info.applicationInfo.uid == uid))
1710 && mSettings.isEnabledLP(p.info, flags)
1711 && (!mSafeMode || (p.info.applicationInfo.flags
1712 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
1713 if (finalList == null) {
1714 finalList = new ArrayList<ProviderInfo>(3);
1715 }
1716 finalList.add(PackageParser.generateProviderInfo(p,
1717 flags));
1718 }
1719 }
1720 }
1721
1722 if (finalList != null) {
1723 Collections.sort(finalList, mProviderInitOrderSorter);
1724 }
1725
1726 return finalList;
1727 }
1728
1729 public InstrumentationInfo getInstrumentationInfo(ComponentName name,
1730 int flags) {
1731 synchronized (mPackages) {
1732 final PackageParser.Instrumentation i = mInstrumentation.get(name);
1733 return PackageParser.generateInstrumentationInfo(i, flags);
1734 }
1735 }
1736
1737 public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
1738 int flags) {
1739 ArrayList<InstrumentationInfo> finalList =
1740 new ArrayList<InstrumentationInfo>();
1741
1742 synchronized (mPackages) {
1743 Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
1744 while (i.hasNext()) {
1745 PackageParser.Instrumentation p = i.next();
1746 if (targetPackage == null
1747 || targetPackage.equals(p.info.targetPackage)) {
1748 finalList.add(PackageParser.generateInstrumentationInfo(p,
1749 flags));
1750 }
1751 }
1752 }
1753
1754 return finalList;
1755 }
1756
1757 private void scanDirLI(File dir, int flags, int scanMode) {
1758 Log.d(TAG, "Scanning app dir " + dir);
1759
1760 String[] files = dir.list();
1761
1762 int i;
1763 for (i=0; i<files.length; i++) {
1764 File file = new File(dir, files[i]);
1765 PackageParser.Package pkg = scanPackageLI(file, file, file,
1766 flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
1767 }
1768 }
1769
1770 private static void reportSettingsProblem(int priority, String msg) {
1771 try {
1772 File dataDir = Environment.getDataDirectory();
1773 File systemDir = new File(dataDir, "system");
1774 File fname = new File(systemDir, "uiderrors.txt");
1775 FileOutputStream out = new FileOutputStream(fname, true);
1776 PrintWriter pw = new PrintWriter(out);
1777 pw.println(msg);
1778 pw.close();
1779 FileUtils.setPermissions(
1780 fname.toString(),
1781 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
1782 -1, -1);
1783 } catch (java.io.IOException e) {
1784 }
1785 Log.println(priority, TAG, msg);
1786 }
1787
1788 private boolean collectCertificatesLI(PackageParser pp, PackageSetting ps,
1789 PackageParser.Package pkg, File srcFile, int parseFlags) {
1790 if (GET_CERTIFICATES) {
1791 if (ps == null || !ps.codePath.equals(srcFile)
1792 || ps.getTimeStamp() != srcFile.lastModified()) {
1793 Log.i(TAG, srcFile.toString() + " changed; collecting certs");
1794 if (!pp.collectCertificates(pkg, parseFlags)) {
1795 mLastScanError = pp.getParseError();
1796 return false;
1797 }
1798 }
1799 }
1800 return true;
1801 }
1802
1803 /*
1804 * Scan a package and return the newly parsed package.
1805 * Returns null in case of errors and the error code is stored in mLastScanError
1806 */
1807 private PackageParser.Package scanPackageLI(File scanFile,
1808 File destCodeFile, File destResourceFile, int parseFlags,
1809 int scanMode) {
1810 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
1811 parseFlags |= mDefParseFlags;
1812 PackageParser pp = new PackageParser(scanFile.getPath());
1813 pp.setSeparateProcesses(mSeparateProcesses);
Dianne Hackborn851a5412009-05-08 12:06:44 -07001814 pp.setSdkVersion(mSdkVersion, mSdkCodename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 final PackageParser.Package pkg = pp.parsePackage(scanFile,
1816 destCodeFile.getAbsolutePath(), mMetrics, parseFlags);
1817 if (pkg == null) {
1818 mLastScanError = pp.getParseError();
1819 return null;
1820 }
1821 PackageSetting ps;
1822 PackageSetting updatedPkg;
1823 synchronized (mPackages) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07001824 ps = mSettings.peekPackageLP(pkg.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName);
1826 }
1827 if (updatedPkg != null) {
1828 // An updated system app will not have the PARSE_IS_SYSTEM flag set initially
1829 parseFlags |= PackageParser.PARSE_IS_SYSTEM;
1830 }
1831 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
1832 // Check for updated system applications here
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07001833 if (updatedPkg != null) {
1834 if ((ps != null) && (!ps.codePath.getPath().equals(scanFile.getPath()))) {
1835 if (pkg.mVersionCode <= ps.versionCode) {
1836 // The system package has been updated and the code path does not match
1837 // Ignore entry. Just return
1838 Log.w(TAG, "Package:" + pkg.packageName +
1839 " has been updated. Ignoring the one from path:"+scanFile);
1840 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
1841 return null;
1842 } else {
1843 // Delete the older apk pointed to by ps
1844 deletePackageResourcesLI(ps.name, ps.codePathString, ps.resourcePathString);
1845 mSettings.enableSystemPackageLP(ps.name);
1846 }
1847 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 }
1849 }
1850 if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
1851 Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
1852 return null;
1853 }
1854 // The apk is forward locked (not public) if its code and resources
1855 // are kept in different files.
1856 if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
1857 scanMode |= SCAN_FORWARD_LOCKED;
1858 }
1859 // Note that we invoke the following method only if we are about to unpack an application
1860 return scanPackageLI(scanFile, destCodeFile, destResourceFile,
1861 pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
1862 }
1863
1864 private static String fixProcessName(String defProcessName,
1865 String processName, int uid) {
1866 if (processName == null) {
1867 return defProcessName;
1868 }
1869 return processName;
1870 }
1871
1872 private boolean verifySignaturesLP(PackageSetting pkgSetting,
1873 PackageParser.Package pkg, int parseFlags, boolean updateSignature) {
1874 if (pkg.mSignatures != null) {
1875 if (!pkgSetting.signatures.updateSignatures(pkg.mSignatures,
1876 updateSignature)) {
1877 Log.e(TAG, "Package " + pkg.packageName
1878 + " signatures do not match the previously installed version; ignoring!");
1879 mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
1880 return false;
1881 }
1882
1883 if (pkgSetting.sharedUser != null) {
1884 if (!pkgSetting.sharedUser.signatures.mergeSignatures(
1885 pkg.mSignatures, updateSignature)) {
1886 Log.e(TAG, "Package " + pkg.packageName
1887 + " has no signatures that match those in shared user "
1888 + pkgSetting.sharedUser.name + "; ignoring!");
1889 mLastScanError = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
1890 return false;
1891 }
1892 }
1893 } else {
1894 pkg.mSignatures = pkgSetting.signatures.mSignatures;
1895 }
1896 return true;
1897 }
1898
1899 private PackageParser.Package scanPackageLI(
1900 File scanFile, File destCodeFile, File destResourceFile,
1901 PackageParser.Package pkg, int parseFlags, int scanMode) {
1902
1903 mScanningPath = scanFile;
1904 if (pkg == null) {
1905 mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1906 return null;
1907 }
1908
1909 final String pkgName = pkg.applicationInfo.packageName;
1910 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
1911 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
1912 }
1913
1914 if (pkgName.equals("android")) {
1915 synchronized (mPackages) {
1916 if (mAndroidApplication != null) {
1917 Log.w(TAG, "*************************************************");
1918 Log.w(TAG, "Core android package being redefined. Skipping.");
1919 Log.w(TAG, " file=" + mScanningPath);
1920 Log.w(TAG, "*************************************************");
1921 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
1922 return null;
1923 }
1924
1925 // Set up information for our fall-back user intent resolution
1926 // activity.
1927 mPlatformPackage = pkg;
1928 pkg.mVersionCode = mSdkVersion;
1929 mAndroidApplication = pkg.applicationInfo;
1930 mResolveActivity.applicationInfo = mAndroidApplication;
1931 mResolveActivity.name = ResolverActivity.class.getName();
1932 mResolveActivity.packageName = mAndroidApplication.packageName;
1933 mResolveActivity.processName = mAndroidApplication.processName;
1934 mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
1935 mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
1936 mResolveActivity.theme = com.android.internal.R.style.Theme_Dialog_Alert;
1937 mResolveActivity.exported = true;
1938 mResolveActivity.enabled = true;
1939 mResolveInfo.activityInfo = mResolveActivity;
1940 mResolveInfo.priority = 0;
1941 mResolveInfo.preferredOrder = 0;
1942 mResolveInfo.match = 0;
1943 mResolveComponentName = new ComponentName(
1944 mAndroidApplication.packageName, mResolveActivity.name);
1945 }
1946 }
1947
1948 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
1949 TAG, "Scanning package " + pkgName);
1950 if (mPackages.containsKey(pkgName) || mSharedLibraries.containsKey(pkgName)) {
1951 Log.w(TAG, "*************************************************");
1952 Log.w(TAG, "Application package " + pkgName
1953 + " already installed. Skipping duplicate.");
1954 Log.w(TAG, "*************************************************");
1955 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
1956 return null;
1957 }
1958
1959 SharedUserSetting suid = null;
1960 PackageSetting pkgSetting = null;
1961
1962 boolean removeExisting = false;
1963
1964 synchronized (mPackages) {
1965 // Check all shared libraries and map to their actual file path.
1966 if (pkg.usesLibraryFiles != null) {
1967 for (int i=0; i<pkg.usesLibraryFiles.length; i++) {
1968 String file = mSharedLibraries.get(pkg.usesLibraryFiles[i]);
1969 if (file == null) {
1970 Log.e(TAG, "Package " + pkg.packageName
1971 + " requires unavailable shared library "
1972 + pkg.usesLibraryFiles[i] + "; ignoring!");
1973 mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
1974 return null;
1975 }
1976 pkg.usesLibraryFiles[i] = file;
1977 }
1978 }
1979
1980 if (pkg.mSharedUserId != null) {
1981 suid = mSettings.getSharedUserLP(pkg.mSharedUserId,
1982 pkg.applicationInfo.flags, true);
1983 if (suid == null) {
1984 Log.w(TAG, "Creating application package " + pkgName
1985 + " for shared user failed");
1986 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
1987 return null;
1988 }
1989 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) {
1990 Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid="
1991 + suid.userId + "): packages=" + suid.packages);
1992 }
1993 }
1994
1995 // Just create the setting, don't add it yet
1996 pkgSetting = mSettings.getPackageLP(pkg, suid, destCodeFile,
1997 destResourceFile, pkg.applicationInfo.flags, true, false);
1998 if (pkgSetting == null) {
1999 Log.w(TAG, "Creating application package " + pkgName + " failed");
2000 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2001 return null;
2002 }
2003 if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
2004 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
2005 }
2006
2007 pkg.applicationInfo.uid = pkgSetting.userId;
2008 pkg.mExtras = pkgSetting;
2009
2010 if (!verifySignaturesLP(pkgSetting, pkg, parseFlags,
2011 (scanMode&SCAN_UPDATE_SIGNATURE) != 0)) {
2012 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) {
2013 mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
2014 return null;
2015 }
2016 // The signature has changed, but this package is in the system
2017 // image... let's recover!
Suchi Amalapurapuc4dd60f2009-03-24 21:10:53 -07002018 pkgSetting.signatures.mSignatures = pkg.mSignatures;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 // However... if this package is part of a shared user, but it
2020 // doesn't match the signature of the shared user, let's fail.
2021 // What this means is that you can't change the signatures
2022 // associated with an overall shared user, which doesn't seem all
2023 // that unreasonable.
2024 if (pkgSetting.sharedUser != null) {
2025 if (!pkgSetting.sharedUser.signatures.mergeSignatures(
2026 pkg.mSignatures, false)) {
2027 mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
2028 return null;
2029 }
2030 }
2031 removeExisting = true;
2032 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002033
2034 // Verify that this new package doesn't have any content providers
2035 // that conflict with existing packages. Only do this if the
2036 // package isn't already installed, since we don't want to break
2037 // things that are installed.
2038 if ((scanMode&SCAN_NEW_INSTALL) != 0) {
2039 int N = pkg.providers.size();
2040 int i;
2041 for (i=0; i<N; i++) {
2042 PackageParser.Provider p = pkg.providers.get(i);
2043 String names[] = p.info.authority.split(";");
2044 for (int j = 0; j < names.length; j++) {
2045 if (mProviders.containsKey(names[j])) {
2046 PackageParser.Provider other = mProviders.get(names[j]);
2047 Log.w(TAG, "Can't install because provider name " + names[j] +
2048 " (in package " + pkg.applicationInfo.packageName +
2049 ") is already used by "
2050 + ((other != null && other.component != null)
2051 ? other.component.getPackageName() : "?"));
2052 mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
2053 return null;
2054 }
2055 }
2056 }
2057 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 }
2059
2060 if (removeExisting) {
2061 if (mInstaller != null) {
2062 int ret = mInstaller.remove(pkgName);
2063 if (ret != 0) {
2064 String msg = "System package " + pkg.packageName
2065 + " could not have data directory erased after signature change.";
2066 reportSettingsProblem(Log.WARN, msg);
2067 mLastScanError = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
2068 return null;
2069 }
2070 }
2071 Log.w(TAG, "System package " + pkg.packageName
2072 + " signature changed: existing data removed.");
2073 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
2074 }
2075
2076 long scanFileTime = scanFile.lastModified();
2077 final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
2078 final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp();
2079 pkg.applicationInfo.processName = fixProcessName(
2080 pkg.applicationInfo.packageName,
2081 pkg.applicationInfo.processName,
2082 pkg.applicationInfo.uid);
2083 pkg.applicationInfo.publicSourceDir = pkgSetting.resourcePathString;
2084
2085 File dataPath;
2086 if (mPlatformPackage == pkg) {
2087 // The system package is special.
2088 dataPath = new File (Environment.getDataDirectory(), "system");
2089 pkg.applicationInfo.dataDir = dataPath.getPath();
2090 } else {
2091 // This is a normal package, need to make its data directory.
2092 dataPath = new File(mAppDataDir, pkgName);
2093 if (dataPath.exists()) {
2094 mOutPermissions[1] = 0;
2095 FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
2096 if (mOutPermissions[1] == pkg.applicationInfo.uid
2097 || !Process.supportsProcesses()) {
2098 pkg.applicationInfo.dataDir = dataPath.getPath();
2099 } else {
2100 boolean recovered = false;
2101 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
2102 // If this is a system app, we can at least delete its
2103 // current data so the application will still work.
2104 if (mInstaller != null) {
2105 int ret = mInstaller.remove(pkgName);
2106 if(ret >= 0) {
2107 // Old data gone!
2108 String msg = "System package " + pkg.packageName
2109 + " has changed from uid: "
2110 + mOutPermissions[1] + " to "
2111 + pkg.applicationInfo.uid + "; old data erased";
2112 reportSettingsProblem(Log.WARN, msg);
2113 recovered = true;
2114
2115 // And now re-install the app.
2116 ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
2117 pkg.applicationInfo.uid);
2118 if (ret == -1) {
2119 // Ack should not happen!
2120 msg = "System package " + pkg.packageName
2121 + " could not have data directory re-created after delete.";
2122 reportSettingsProblem(Log.WARN, msg);
2123 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2124 return null;
2125 }
2126 }
2127 }
2128 if (!recovered) {
2129 mHasSystemUidErrors = true;
2130 }
2131 }
2132 if (!recovered) {
2133 pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
2134 + pkg.applicationInfo.uid + "/fs_"
2135 + mOutPermissions[1];
2136 String msg = "Package " + pkg.packageName
2137 + " has mismatched uid: "
2138 + mOutPermissions[1] + " on disk, "
2139 + pkg.applicationInfo.uid + " in settings";
2140 synchronized (mPackages) {
2141 if (!mReportedUidError) {
2142 mReportedUidError = true;
2143 msg = msg + "; read messages:\n"
2144 + mSettings.getReadMessagesLP();
2145 }
2146 reportSettingsProblem(Log.ERROR, msg);
2147 }
2148 }
2149 }
2150 pkg.applicationInfo.dataDir = dataPath.getPath();
2151 } else {
2152 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGV)
2153 Log.v(TAG, "Want this data dir: " + dataPath);
2154 //invoke installer to do the actual installation
2155 if (mInstaller != null) {
2156 int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
2157 pkg.applicationInfo.uid);
2158 if(ret < 0) {
2159 // Error from installer
2160 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2161 return null;
2162 }
2163 } else {
2164 dataPath.mkdirs();
2165 if (dataPath.exists()) {
2166 FileUtils.setPermissions(
2167 dataPath.toString(),
2168 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
2169 pkg.applicationInfo.uid, pkg.applicationInfo.uid);
2170 }
2171 }
2172 if (dataPath.exists()) {
2173 pkg.applicationInfo.dataDir = dataPath.getPath();
2174 } else {
2175 Log.w(TAG, "Unable to create data directory: " + dataPath);
2176 pkg.applicationInfo.dataDir = null;
2177 }
2178 }
2179 }
2180
2181 // Perform shared library installation and dex validation and
2182 // optimization, if this is not a system app.
2183 if (mInstaller != null) {
2184 String path = scanFile.getPath();
2185 if (scanFileNewer) {
2186 Log.i(TAG, path + " changed; unpacking");
Dianne Hackbornb1811182009-05-21 15:45:42 -07002187 int err = cachePackageSharedLibsLI(pkg, dataPath, scanFile);
2188 if (err != PackageManager.INSTALL_SUCCEEDED) {
2189 mLastScanError = err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 return null;
2191 }
2192 }
2193
2194 if ((scanMode&SCAN_NO_DEX) == 0
2195 && (pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
2196 int ret = 0;
2197 try {
2198 if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
2199 ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
2200 (scanMode&SCAN_FORWARD_LOCKED) == 0);
2201 }
2202 } catch (FileNotFoundException e) {
2203 Log.w(TAG, "Apk not found for dexopt: " + path);
2204 ret = -1;
2205 } catch (IOException e) {
2206 Log.w(TAG, "Exception reading apk: " + path, e);
2207 ret = -1;
2208 }
2209 if (ret < 0) {
2210 //error from installer
2211 mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
2212 return null;
2213 }
2214 }
2215 }
2216
2217 if (mFactoryTest && pkg.requestedPermissions.contains(
2218 android.Manifest.permission.FACTORY_TEST)) {
2219 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
2220 }
2221
2222 if ((scanMode&SCAN_MONITOR) != 0) {
2223 pkg.mPath = destCodeFile.getAbsolutePath();
2224 mAppDirs.put(pkg.mPath, pkg);
2225 }
2226
2227 synchronized (mPackages) {
2228 // We don't expect installation to fail beyond this point
2229 // Add the new setting to mSettings
2230 mSettings.insertPackageSettingLP(pkgSetting, pkg.packageName, suid);
2231 // Add the new setting to mPackages
2232 mPackages.put(pkg.applicationInfo.packageName, pkg);
2233 int N = pkg.providers.size();
2234 StringBuilder r = null;
2235 int i;
2236 for (i=0; i<N; i++) {
2237 PackageParser.Provider p = pkg.providers.get(i);
2238 p.info.processName = fixProcessName(pkg.applicationInfo.processName,
2239 p.info.processName, pkg.applicationInfo.uid);
2240 mProvidersByComponent.put(new ComponentName(p.info.packageName,
2241 p.info.name), p);
2242 p.syncable = p.info.isSyncable;
2243 String names[] = p.info.authority.split(";");
2244 p.info.authority = null;
2245 for (int j = 0; j < names.length; j++) {
2246 if (j == 1 && p.syncable) {
2247 // We only want the first authority for a provider to possibly be
2248 // syncable, so if we already added this provider using a different
2249 // authority clear the syncable flag. We copy the provider before
2250 // changing it because the mProviders object contains a reference
2251 // to a provider that we don't want to change.
2252 // Only do this for the second authority since the resulting provider
2253 // object can be the same for all future authorities for this provider.
2254 p = new PackageParser.Provider(p);
2255 p.syncable = false;
2256 }
2257 if (!mProviders.containsKey(names[j])) {
2258 mProviders.put(names[j], p);
2259 if (p.info.authority == null) {
2260 p.info.authority = names[j];
2261 } else {
2262 p.info.authority = p.info.authority + ";" + names[j];
2263 }
2264 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD)
2265 Log.d(TAG, "Registered content provider: " + names[j] +
2266 ", className = " + p.info.name +
2267 ", isSyncable = " + p.info.isSyncable);
2268 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07002269 PackageParser.Provider other = mProviders.get(names[j]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002270 Log.w(TAG, "Skipping provider name " + names[j] +
2271 " (in package " + pkg.applicationInfo.packageName +
The Android Open Source Project10592532009-03-18 17:39:46 -07002272 "): name already used by "
2273 + ((other != null && other.component != null)
2274 ? other.component.getPackageName() : "?"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275 }
2276 }
2277 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2278 if (r == null) {
2279 r = new StringBuilder(256);
2280 } else {
2281 r.append(' ');
2282 }
2283 r.append(p.info.name);
2284 }
2285 }
2286 if (r != null) {
2287 if (Config.LOGD) Log.d(TAG, " Providers: " + r);
2288 }
2289
2290 N = pkg.services.size();
2291 r = null;
2292 for (i=0; i<N; i++) {
2293 PackageParser.Service s = pkg.services.get(i);
2294 s.info.processName = fixProcessName(pkg.applicationInfo.processName,
2295 s.info.processName, pkg.applicationInfo.uid);
2296 mServices.addService(s);
2297 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2298 if (r == null) {
2299 r = new StringBuilder(256);
2300 } else {
2301 r.append(' ');
2302 }
2303 r.append(s.info.name);
2304 }
2305 }
2306 if (r != null) {
2307 if (Config.LOGD) Log.d(TAG, " Services: " + r);
2308 }
2309
2310 N = pkg.receivers.size();
2311 r = null;
2312 for (i=0; i<N; i++) {
2313 PackageParser.Activity a = pkg.receivers.get(i);
2314 a.info.processName = fixProcessName(pkg.applicationInfo.processName,
2315 a.info.processName, pkg.applicationInfo.uid);
2316 mReceivers.addActivity(a, "receiver");
2317 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2318 if (r == null) {
2319 r = new StringBuilder(256);
2320 } else {
2321 r.append(' ');
2322 }
2323 r.append(a.info.name);
2324 }
2325 }
2326 if (r != null) {
2327 if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
2328 }
2329
2330 N = pkg.activities.size();
2331 r = null;
2332 for (i=0; i<N; i++) {
2333 PackageParser.Activity a = pkg.activities.get(i);
2334 a.info.processName = fixProcessName(pkg.applicationInfo.processName,
2335 a.info.processName, pkg.applicationInfo.uid);
2336 mActivities.addActivity(a, "activity");
2337 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2338 if (r == null) {
2339 r = new StringBuilder(256);
2340 } else {
2341 r.append(' ');
2342 }
2343 r.append(a.info.name);
2344 }
2345 }
2346 if (r != null) {
2347 if (Config.LOGD) Log.d(TAG, " Activities: " + r);
2348 }
2349
2350 N = pkg.permissionGroups.size();
2351 r = null;
2352 for (i=0; i<N; i++) {
2353 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
2354 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
2355 if (cur == null) {
2356 mPermissionGroups.put(pg.info.name, pg);
2357 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2358 if (r == null) {
2359 r = new StringBuilder(256);
2360 } else {
2361 r.append(' ');
2362 }
2363 r.append(pg.info.name);
2364 }
2365 } else {
2366 Log.w(TAG, "Permission group " + pg.info.name + " from package "
2367 + pg.info.packageName + " ignored: original from "
2368 + cur.info.packageName);
2369 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2370 if (r == null) {
2371 r = new StringBuilder(256);
2372 } else {
2373 r.append(' ');
2374 }
2375 r.append("DUP:");
2376 r.append(pg.info.name);
2377 }
2378 }
2379 }
2380 if (r != null) {
2381 if (Config.LOGD) Log.d(TAG, " Permission Groups: " + r);
2382 }
2383
2384 N = pkg.permissions.size();
2385 r = null;
2386 for (i=0; i<N; i++) {
2387 PackageParser.Permission p = pkg.permissions.get(i);
2388 HashMap<String, BasePermission> permissionMap =
2389 p.tree ? mSettings.mPermissionTrees
2390 : mSettings.mPermissions;
2391 p.group = mPermissionGroups.get(p.info.group);
2392 if (p.info.group == null || p.group != null) {
2393 BasePermission bp = permissionMap.get(p.info.name);
2394 if (bp == null) {
2395 bp = new BasePermission(p.info.name, p.info.packageName,
2396 BasePermission.TYPE_NORMAL);
2397 permissionMap.put(p.info.name, bp);
2398 }
2399 if (bp.perm == null) {
2400 if (bp.sourcePackage == null
2401 || bp.sourcePackage.equals(p.info.packageName)) {
2402 BasePermission tree = findPermissionTreeLP(p.info.name);
2403 if (tree == null
2404 || tree.sourcePackage.equals(p.info.packageName)) {
2405 bp.perm = p;
2406 bp.uid = pkg.applicationInfo.uid;
2407 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2408 if (r == null) {
2409 r = new StringBuilder(256);
2410 } else {
2411 r.append(' ');
2412 }
2413 r.append(p.info.name);
2414 }
2415 } else {
2416 Log.w(TAG, "Permission " + p.info.name + " from package "
2417 + p.info.packageName + " ignored: base tree "
2418 + tree.name + " is from package "
2419 + tree.sourcePackage);
2420 }
2421 } else {
2422 Log.w(TAG, "Permission " + p.info.name + " from package "
2423 + p.info.packageName + " ignored: original from "
2424 + bp.sourcePackage);
2425 }
2426 } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2427 if (r == null) {
2428 r = new StringBuilder(256);
2429 } else {
2430 r.append(' ');
2431 }
2432 r.append("DUP:");
2433 r.append(p.info.name);
2434 }
2435 } else {
2436 Log.w(TAG, "Permission " + p.info.name + " from package "
2437 + p.info.packageName + " ignored: no group "
2438 + p.group);
2439 }
2440 }
2441 if (r != null) {
2442 if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
2443 }
2444
2445 N = pkg.instrumentation.size();
2446 r = null;
2447 for (i=0; i<N; i++) {
2448 PackageParser.Instrumentation a = pkg.instrumentation.get(i);
2449 a.info.packageName = pkg.applicationInfo.packageName;
2450 a.info.sourceDir = pkg.applicationInfo.sourceDir;
2451 a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
2452 a.info.dataDir = pkg.applicationInfo.dataDir;
2453 mInstrumentation.put(a.component, a);
2454 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2455 if (r == null) {
2456 r = new StringBuilder(256);
2457 } else {
2458 r.append(' ');
2459 }
2460 r.append(a.info.name);
2461 }
2462 }
2463 if (r != null) {
2464 if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
2465 }
2466
2467 pkgSetting.setTimeStamp(scanFileTime);
2468 }
2469
2470 return pkg;
2471 }
2472
Dianne Hackbornb1811182009-05-21 15:45:42 -07002473 private int cachePackageSharedLibsLI(PackageParser.Package pkg,
2474 File dataPath, File scanFile) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 File sharedLibraryDir = new File(dataPath.getPath() + "/lib");
Dianne Hackbornb1811182009-05-21 15:45:42 -07002476 final String sharedLibraryABI = Build.CPU_ABI;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002477 final String apkLibraryDirectory = "lib/" + sharedLibraryABI + "/";
2478 final String apkSharedLibraryPrefix = apkLibraryDirectory + "lib";
2479 final String sharedLibrarySuffix = ".so";
Dianne Hackbornb1811182009-05-21 15:45:42 -07002480 boolean hasNativeCode = false;
2481 boolean installedNativeCode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002482 try {
2483 ZipFile zipFile = new ZipFile(scanFile);
2484 Enumeration<ZipEntry> entries =
2485 (Enumeration<ZipEntry>) zipFile.entries();
2486
2487 while (entries.hasMoreElements()) {
2488 ZipEntry entry = entries.nextElement();
2489 if (entry.isDirectory()) {
Dianne Hackbornb1811182009-05-21 15:45:42 -07002490 if (!hasNativeCode && entry.getName().startsWith("lib")) {
2491 hasNativeCode = true;
2492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 continue;
2494 }
2495 String entryName = entry.getName();
Dianne Hackbornb1811182009-05-21 15:45:42 -07002496 if (entryName.startsWith("lib/")) {
2497 hasNativeCode = true;
2498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002499 if (! (entryName.startsWith(apkSharedLibraryPrefix)
2500 && entryName.endsWith(sharedLibrarySuffix))) {
2501 continue;
2502 }
2503 String libFileName = entryName.substring(
2504 apkLibraryDirectory.length());
2505 if (libFileName.contains("/")
2506 || (!FileUtils.isFilenameSafe(new File(libFileName)))) {
2507 continue;
2508 }
Dianne Hackbornb1811182009-05-21 15:45:42 -07002509
2510 installedNativeCode = true;
2511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002512 String sharedLibraryFilePath = sharedLibraryDir.getPath() +
2513 File.separator + libFileName;
2514 File sharedLibraryFile = new File(sharedLibraryFilePath);
2515 if (! sharedLibraryFile.exists() ||
2516 sharedLibraryFile.length() != entry.getSize() ||
2517 sharedLibraryFile.lastModified() != entry.getTime()) {
2518 if (Config.LOGD) {
2519 Log.d(TAG, "Caching shared lib " + entry.getName());
2520 }
2521 if (mInstaller == null) {
2522 sharedLibraryDir.mkdir();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 }
2524 cacheSharedLibLI(pkg, zipFile, entry, sharedLibraryDir,
2525 sharedLibraryFile);
2526 }
2527 }
2528 } catch (IOException e) {
Dianne Hackbornb1811182009-05-21 15:45:42 -07002529 Log.w(TAG, "Failed to cache package shared libs", e);
2530 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002531 }
Dianne Hackbornb1811182009-05-21 15:45:42 -07002532
2533 if (hasNativeCode && !installedNativeCode) {
2534 Log.w(TAG, "Install failed: .apk has native code but none for arch "
2535 + Build.CPU_ABI);
2536 return PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
2537 }
2538
2539 return PackageManager.INSTALL_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 }
2541
2542 private void cacheSharedLibLI(PackageParser.Package pkg,
2543 ZipFile zipFile, ZipEntry entry,
2544 File sharedLibraryDir,
2545 File sharedLibraryFile) throws IOException {
2546 InputStream inputStream = zipFile.getInputStream(entry);
2547 try {
2548 File tempFile = File.createTempFile("tmp", "tmp", sharedLibraryDir);
2549 String tempFilePath = tempFile.getPath();
2550 // XXX package manager can't change owner, so the lib files for
2551 // now need to be left as world readable and owned by the system.
2552 if (! FileUtils.copyToFile(inputStream, tempFile) ||
2553 ! tempFile.setLastModified(entry.getTime()) ||
2554 FileUtils.setPermissions(tempFilePath,
2555 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
2556 |FileUtils.S_IROTH, -1, -1) != 0 ||
2557 ! tempFile.renameTo(sharedLibraryFile)) {
2558 // Failed to properly write file.
2559 tempFile.delete();
2560 throw new IOException("Couldn't create cached shared lib "
2561 + sharedLibraryFile + " in " + sharedLibraryDir);
2562 }
2563 } finally {
2564 inputStream.close();
2565 }
2566 }
2567
2568 void removePackageLI(PackageParser.Package pkg, boolean chatty) {
2569 if (chatty && Config.LOGD) Log.d(
2570 TAG, "Removing package " + pkg.applicationInfo.packageName );
2571
2572 synchronized (mPackages) {
2573 if (pkg.mPreferredOrder > 0) {
2574 mSettings.mPreferredPackages.remove(pkg);
2575 pkg.mPreferredOrder = 0;
2576 updatePreferredIndicesLP();
2577 }
2578
2579 clearPackagePreferredActivitiesLP(pkg.packageName);
2580
2581 mPackages.remove(pkg.applicationInfo.packageName);
2582 if (pkg.mPath != null) {
2583 mAppDirs.remove(pkg.mPath);
2584 }
2585
2586 PackageSetting ps = (PackageSetting)pkg.mExtras;
2587 if (ps != null && ps.sharedUser != null) {
2588 // XXX don't do this until the data is removed.
2589 if (false) {
2590 ps.sharedUser.packages.remove(ps);
2591 if (ps.sharedUser.packages.size() == 0) {
2592 // Remove.
2593 }
2594 }
2595 }
2596
2597 int N = pkg.providers.size();
2598 StringBuilder r = null;
2599 int i;
2600 for (i=0; i<N; i++) {
2601 PackageParser.Provider p = pkg.providers.get(i);
2602 mProvidersByComponent.remove(new ComponentName(p.info.packageName,
2603 p.info.name));
2604 if (p.info.authority == null) {
2605
2606 /* The is another ContentProvider with this authority when
2607 * this app was installed so this authority is null,
2608 * Ignore it as we don't have to unregister the provider.
2609 */
2610 continue;
2611 }
2612 String names[] = p.info.authority.split(";");
2613 for (int j = 0; j < names.length; j++) {
2614 if (mProviders.get(names[j]) == p) {
2615 mProviders.remove(names[j]);
2616 if (chatty && Config.LOGD) Log.d(
2617 TAG, "Unregistered content provider: " + names[j] +
2618 ", className = " + p.info.name +
2619 ", isSyncable = " + p.info.isSyncable);
2620 }
2621 }
2622 if (chatty) {
2623 if (r == null) {
2624 r = new StringBuilder(256);
2625 } else {
2626 r.append(' ');
2627 }
2628 r.append(p.info.name);
2629 }
2630 }
2631 if (r != null) {
2632 if (Config.LOGD) Log.d(TAG, " Providers: " + r);
2633 }
2634
2635 N = pkg.services.size();
2636 r = null;
2637 for (i=0; i<N; i++) {
2638 PackageParser.Service s = pkg.services.get(i);
2639 mServices.removeService(s);
2640 if (chatty) {
2641 if (r == null) {
2642 r = new StringBuilder(256);
2643 } else {
2644 r.append(' ');
2645 }
2646 r.append(s.info.name);
2647 }
2648 }
2649 if (r != null) {
2650 if (Config.LOGD) Log.d(TAG, " Services: " + r);
2651 }
2652
2653 N = pkg.receivers.size();
2654 r = null;
2655 for (i=0; i<N; i++) {
2656 PackageParser.Activity a = pkg.receivers.get(i);
2657 mReceivers.removeActivity(a, "receiver");
2658 if (chatty) {
2659 if (r == null) {
2660 r = new StringBuilder(256);
2661 } else {
2662 r.append(' ');
2663 }
2664 r.append(a.info.name);
2665 }
2666 }
2667 if (r != null) {
2668 if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
2669 }
2670
2671 N = pkg.activities.size();
2672 r = null;
2673 for (i=0; i<N; i++) {
2674 PackageParser.Activity a = pkg.activities.get(i);
2675 mActivities.removeActivity(a, "activity");
2676 if (chatty) {
2677 if (r == null) {
2678 r = new StringBuilder(256);
2679 } else {
2680 r.append(' ');
2681 }
2682 r.append(a.info.name);
2683 }
2684 }
2685 if (r != null) {
2686 if (Config.LOGD) Log.d(TAG, " Activities: " + r);
2687 }
2688
2689 N = pkg.permissions.size();
2690 r = null;
2691 for (i=0; i<N; i++) {
2692 PackageParser.Permission p = pkg.permissions.get(i);
2693 boolean tree = false;
2694 BasePermission bp = mSettings.mPermissions.get(p.info.name);
2695 if (bp == null) {
2696 tree = true;
2697 bp = mSettings.mPermissionTrees.get(p.info.name);
2698 }
2699 if (bp != null && bp.perm == p) {
2700 if (bp.type != BasePermission.TYPE_BUILTIN) {
2701 if (tree) {
2702 mSettings.mPermissionTrees.remove(p.info.name);
2703 } else {
2704 mSettings.mPermissions.remove(p.info.name);
2705 }
2706 } else {
2707 bp.perm = null;
2708 }
2709 if (chatty) {
2710 if (r == null) {
2711 r = new StringBuilder(256);
2712 } else {
2713 r.append(' ');
2714 }
2715 r.append(p.info.name);
2716 }
2717 }
2718 }
2719 if (r != null) {
2720 if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
2721 }
2722
2723 N = pkg.instrumentation.size();
2724 r = null;
2725 for (i=0; i<N; i++) {
2726 PackageParser.Instrumentation a = pkg.instrumentation.get(i);
2727 mInstrumentation.remove(a.component);
2728 if (chatty) {
2729 if (r == null) {
2730 r = new StringBuilder(256);
2731 } else {
2732 r.append(' ');
2733 }
2734 r.append(a.info.name);
2735 }
2736 }
2737 if (r != null) {
2738 if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
2739 }
2740 }
2741 }
2742
2743 private static final boolean isPackageFilename(String name) {
2744 return name != null && name.endsWith(".apk");
2745 }
2746
2747 private void updatePermissionsLP() {
2748 // Make sure there are no dangling permission trees.
2749 Iterator<BasePermission> it = mSettings.mPermissionTrees
2750 .values().iterator();
2751 while (it.hasNext()) {
2752 BasePermission bp = it.next();
2753 if (bp.perm == null) {
2754 Log.w(TAG, "Removing dangling permission tree: " + bp.name
2755 + " from package " + bp.sourcePackage);
2756 it.remove();
2757 }
2758 }
2759
2760 // Make sure all dynamic permissions have been assigned to a package,
2761 // and make sure there are no dangling permissions.
2762 it = mSettings.mPermissions.values().iterator();
2763 while (it.hasNext()) {
2764 BasePermission bp = it.next();
2765 if (bp.type == BasePermission.TYPE_DYNAMIC) {
2766 if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
2767 + bp.name + " pkg=" + bp.sourcePackage
2768 + " info=" + bp.pendingInfo);
2769 if (bp.perm == null && bp.pendingInfo != null) {
2770 BasePermission tree = findPermissionTreeLP(bp.name);
2771 if (tree != null) {
2772 bp.perm = new PackageParser.Permission(tree.perm.owner,
2773 new PermissionInfo(bp.pendingInfo));
2774 bp.perm.info.packageName = tree.perm.info.packageName;
2775 bp.perm.info.name = bp.name;
2776 bp.uid = tree.uid;
2777 }
2778 }
2779 }
2780 if (bp.perm == null) {
2781 Log.w(TAG, "Removing dangling permission: " + bp.name
2782 + " from package " + bp.sourcePackage);
2783 it.remove();
2784 }
2785 }
2786
2787 // Now update the permissions for all packages, in particular
2788 // replace the granted permissions of the system packages.
2789 for (PackageParser.Package pkg : mPackages.values()) {
2790 grantPermissionsLP(pkg, false);
2791 }
2792 }
2793
2794 private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) {
2795 final PackageSetting ps = (PackageSetting)pkg.mExtras;
2796 if (ps == null) {
2797 return;
2798 }
2799 final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
2800 boolean addedPermission = false;
2801
2802 if (replace) {
2803 ps.permissionsFixed = false;
2804 if (gp == ps) {
2805 gp.grantedPermissions.clear();
2806 gp.gids = mGlobalGids;
2807 }
2808 }
2809
2810 if (gp.gids == null) {
2811 gp.gids = mGlobalGids;
2812 }
2813
2814 final int N = pkg.requestedPermissions.size();
2815 for (int i=0; i<N; i++) {
2816 String name = pkg.requestedPermissions.get(i);
2817 BasePermission bp = mSettings.mPermissions.get(name);
2818 PackageParser.Permission p = bp != null ? bp.perm : null;
2819 if (false) {
2820 if (gp != ps) {
2821 Log.i(TAG, "Package " + pkg.packageName + " checking " + name
2822 + ": " + p);
2823 }
2824 }
2825 if (p != null) {
2826 final String perm = p.info.name;
2827 boolean allowed;
2828 if (p.info.protectionLevel == PermissionInfo.PROTECTION_NORMAL
2829 || p.info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
2830 allowed = true;
2831 } else if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
2832 || p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
2833 allowed = (checkSignaturesLP(p.owner, pkg)
2834 == PackageManager.SIGNATURE_MATCH)
2835 || (checkSignaturesLP(mPlatformPackage, pkg)
2836 == PackageManager.SIGNATURE_MATCH);
2837 if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
2838 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
2839 // For updated system applications, the signatureOrSystem permission
2840 // is granted only if it had been defined by the original application.
2841 if ((pkg.applicationInfo.flags
2842 & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
2843 PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName);
2844 if(sysPs.grantedPermissions.contains(perm)) {
2845 allowed = true;
2846 } else {
2847 allowed = false;
2848 }
2849 } else {
2850 allowed = true;
2851 }
2852 }
2853 }
2854 } else {
2855 allowed = false;
2856 }
2857 if (false) {
2858 if (gp != ps) {
2859 Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
2860 }
2861 }
2862 if (allowed) {
2863 if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0
2864 && ps.permissionsFixed) {
2865 // If this is an existing, non-system package, then
2866 // we can't add any new permissions to it.
2867 if (!gp.loadedPermissions.contains(perm)) {
2868 allowed = false;
Dianne Hackborna96cbb42009-05-13 15:06:13 -07002869 // Except... if this is a permission that was added
2870 // to the platform (note: need to only do this when
2871 // updating the platform).
2872 final int NP = PackageParser.NEW_PERMISSIONS.length;
2873 for (int ip=0; ip<NP; ip++) {
2874 final PackageParser.NewPermissionInfo npi
2875 = PackageParser.NEW_PERMISSIONS[ip];
2876 if (npi.name.equals(perm)
2877 && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
2878 allowed = true;
San Mehat5a3a77d2009-06-01 09:25:28 -07002879 Log.i(TAG, "Auto-granting WRITE_EXTERNAL_STORAGE to old pkg "
Dianne Hackborna96cbb42009-05-13 15:06:13 -07002880 + pkg.packageName);
2881 break;
2882 }
2883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002884 }
2885 }
2886 if (allowed) {
2887 if (!gp.grantedPermissions.contains(perm)) {
2888 addedPermission = true;
2889 gp.grantedPermissions.add(perm);
2890 gp.gids = appendInts(gp.gids, bp.gids);
2891 }
2892 } else {
2893 Log.w(TAG, "Not granting permission " + perm
2894 + " to package " + pkg.packageName
2895 + " because it was previously installed without");
2896 }
2897 } else {
2898 Log.w(TAG, "Not granting permission " + perm
2899 + " to package " + pkg.packageName
2900 + " (protectionLevel=" + p.info.protectionLevel
2901 + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
2902 + ")");
2903 }
2904 } else {
2905 Log.w(TAG, "Unknown permission " + name
2906 + " in package " + pkg.packageName);
2907 }
2908 }
2909
2910 if ((addedPermission || replace) && !ps.permissionsFixed &&
2911 (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
2912 // This is the first that we have heard about this package, so the
2913 // permissions we have now selected are fixed until explicitly
2914 // changed.
2915 ps.permissionsFixed = true;
2916 gp.loadedPermissions = new HashSet<String>(gp.grantedPermissions);
2917 }
2918 }
2919
2920 private final class ActivityIntentResolver
2921 extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
Mihai Preda074edef2009-05-18 17:13:31 +02002922 public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
Mihai Preda074edef2009-05-18 17:13:31 +02002924 return super.queryIntent(intent, resolvedType, defaultOnly);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 }
2926
Mihai Preda074edef2009-05-18 17:13:31 +02002927 public List queryIntent(Intent intent, String resolvedType, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002928 mFlags = flags;
Mihai Preda074edef2009-05-18 17:13:31 +02002929 return super.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
2931 }
2932
Mihai Predaeae850c2009-05-13 10:13:48 +02002933 public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
2934 ArrayList<PackageParser.Activity> packageActivities) {
2935 if (packageActivities == null) {
2936 return null;
2937 }
2938 mFlags = flags;
2939 final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
2940 int N = packageActivities.size();
2941 ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut =
2942 new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N);
Mihai Predac3320db2009-05-18 20:15:32 +02002943
2944 ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
Mihai Predaeae850c2009-05-13 10:13:48 +02002945 for (int i = 0; i < N; ++i) {
Mihai Predac3320db2009-05-18 20:15:32 +02002946 intentFilters = packageActivities.get(i).intents;
2947 if (intentFilters != null && intentFilters.size() > 0) {
2948 listCut.add(intentFilters);
2949 }
Mihai Predaeae850c2009-05-13 10:13:48 +02002950 }
2951 return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
2952 }
2953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002954 public final void addActivity(PackageParser.Activity a, String type) {
2955 mActivities.put(a.component, a);
2956 if (SHOW_INFO || Config.LOGV) Log.v(
2957 TAG, " " + type + " " +
2958 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
2959 if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
2960 int NI = a.intents.size();
Mihai Predaeae850c2009-05-13 10:13:48 +02002961 for (int j=0; j<NI; j++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002962 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
2963 if (SHOW_INFO || Config.LOGV) {
2964 Log.v(TAG, " IntentFilter:");
2965 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
2966 }
2967 if (!intent.debugCheck()) {
2968 Log.w(TAG, "==> For Activity " + a.info.name);
2969 }
2970 addFilter(intent);
2971 }
2972 }
2973
2974 public final void removeActivity(PackageParser.Activity a, String type) {
2975 mActivities.remove(a.component);
2976 if (SHOW_INFO || Config.LOGV) Log.v(
2977 TAG, " " + type + " " +
2978 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
2979 if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
2980 int NI = a.intents.size();
Mihai Predaeae850c2009-05-13 10:13:48 +02002981 for (int j=0; j<NI; j++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002982 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
2983 if (SHOW_INFO || Config.LOGV) {
2984 Log.v(TAG, " IntentFilter:");
2985 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
2986 }
2987 removeFilter(intent);
2988 }
2989 }
2990
2991 @Override
2992 protected boolean allowFilterResult(
2993 PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {
2994 ActivityInfo filterAi = filter.activity.info;
2995 for (int i=dest.size()-1; i>=0; i--) {
2996 ActivityInfo destAi = dest.get(i).activityInfo;
2997 if (destAi.name == filterAi.name
2998 && destAi.packageName == filterAi.packageName) {
2999 return false;
3000 }
3001 }
3002 return true;
3003 }
3004
3005 @Override
3006 protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
3007 int match) {
3008 if (!mSettings.isEnabledLP(info.activity.info, mFlags)) {
3009 return null;
3010 }
3011 final PackageParser.Activity activity = info.activity;
3012 if (mSafeMode && (activity.info.applicationInfo.flags
3013 &ApplicationInfo.FLAG_SYSTEM) == 0) {
3014 return null;
3015 }
3016 final ResolveInfo res = new ResolveInfo();
3017 res.activityInfo = PackageParser.generateActivityInfo(activity,
3018 mFlags);
3019 if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
3020 res.filter = info;
3021 }
3022 res.priority = info.getPriority();
3023 res.preferredOrder = activity.owner.mPreferredOrder;
3024 //System.out.println("Result: " + res.activityInfo.className +
3025 // " = " + res.priority);
3026 res.match = match;
3027 res.isDefault = info.hasDefault;
3028 res.labelRes = info.labelRes;
3029 res.nonLocalizedLabel = info.nonLocalizedLabel;
3030 res.icon = info.icon;
3031 return res;
3032 }
3033
3034 @Override
3035 protected void sortResults(List<ResolveInfo> results) {
3036 Collections.sort(results, mResolvePrioritySorter);
3037 }
3038
3039 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003040 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003041 PackageParser.ActivityIntentInfo filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003042 out.print(prefix); out.print(
3043 Integer.toHexString(System.identityHashCode(filter.activity)));
3044 out.print(' ');
3045 out.println(filter.activity.componentShortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003046 }
3047
3048// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
3049// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
3050// final List<ResolveInfo> retList = Lists.newArrayList();
3051// while (i.hasNext()) {
3052// final ResolveInfo resolveInfo = i.next();
3053// if (isEnabledLP(resolveInfo.activityInfo)) {
3054// retList.add(resolveInfo);
3055// }
3056// }
3057// return retList;
3058// }
3059
3060 // Keys are String (activity class name), values are Activity.
3061 private final HashMap<ComponentName, PackageParser.Activity> mActivities
3062 = new HashMap<ComponentName, PackageParser.Activity>();
3063 private int mFlags;
3064 }
3065
3066 private final class ServiceIntentResolver
3067 extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
Mihai Preda074edef2009-05-18 17:13:31 +02003068 public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
Mihai Preda074edef2009-05-18 17:13:31 +02003070 return super.queryIntent(intent, resolvedType, defaultOnly);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003071 }
3072
Mihai Preda074edef2009-05-18 17:13:31 +02003073 public List queryIntent(Intent intent, String resolvedType, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 mFlags = flags;
Mihai Preda074edef2009-05-18 17:13:31 +02003075 return super.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
3077 }
3078
3079 public final void addService(PackageParser.Service s) {
3080 mServices.put(s.component, s);
3081 if (SHOW_INFO || Config.LOGV) Log.v(
3082 TAG, " " + (s.info.nonLocalizedLabel != null
3083 ? s.info.nonLocalizedLabel : s.info.name) + ":");
3084 if (SHOW_INFO || Config.LOGV) Log.v(
3085 TAG, " Class=" + s.info.name);
3086 int NI = s.intents.size();
3087 int j;
3088 for (j=0; j<NI; j++) {
3089 PackageParser.ServiceIntentInfo intent = s.intents.get(j);
3090 if (SHOW_INFO || Config.LOGV) {
3091 Log.v(TAG, " IntentFilter:");
3092 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3093 }
3094 if (!intent.debugCheck()) {
3095 Log.w(TAG, "==> For Service " + s.info.name);
3096 }
3097 addFilter(intent);
3098 }
3099 }
3100
3101 public final void removeService(PackageParser.Service s) {
3102 mServices.remove(s.component);
3103 if (SHOW_INFO || Config.LOGV) Log.v(
3104 TAG, " " + (s.info.nonLocalizedLabel != null
3105 ? s.info.nonLocalizedLabel : s.info.name) + ":");
3106 if (SHOW_INFO || Config.LOGV) Log.v(
3107 TAG, " Class=" + s.info.name);
3108 int NI = s.intents.size();
3109 int j;
3110 for (j=0; j<NI; j++) {
3111 PackageParser.ServiceIntentInfo intent = s.intents.get(j);
3112 if (SHOW_INFO || Config.LOGV) {
3113 Log.v(TAG, " IntentFilter:");
3114 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3115 }
3116 removeFilter(intent);
3117 }
3118 }
3119
3120 @Override
3121 protected boolean allowFilterResult(
3122 PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) {
3123 ServiceInfo filterSi = filter.service.info;
3124 for (int i=dest.size()-1; i>=0; i--) {
3125 ServiceInfo destAi = dest.get(i).serviceInfo;
3126 if (destAi.name == filterSi.name
3127 && destAi.packageName == filterSi.packageName) {
3128 return false;
3129 }
3130 }
3131 return true;
3132 }
3133
3134 @Override
3135 protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
3136 int match) {
3137 final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
3138 if (!mSettings.isEnabledLP(info.service.info, mFlags)) {
3139 return null;
3140 }
3141 final PackageParser.Service service = info.service;
3142 if (mSafeMode && (service.info.applicationInfo.flags
3143 &ApplicationInfo.FLAG_SYSTEM) == 0) {
3144 return null;
3145 }
3146 final ResolveInfo res = new ResolveInfo();
3147 res.serviceInfo = PackageParser.generateServiceInfo(service,
3148 mFlags);
3149 if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
3150 res.filter = filter;
3151 }
3152 res.priority = info.getPriority();
3153 res.preferredOrder = service.owner.mPreferredOrder;
3154 //System.out.println("Result: " + res.activityInfo.className +
3155 // " = " + res.priority);
3156 res.match = match;
3157 res.isDefault = info.hasDefault;
3158 res.labelRes = info.labelRes;
3159 res.nonLocalizedLabel = info.nonLocalizedLabel;
3160 res.icon = info.icon;
3161 return res;
3162 }
3163
3164 @Override
3165 protected void sortResults(List<ResolveInfo> results) {
3166 Collections.sort(results, mResolvePrioritySorter);
3167 }
3168
3169 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003170 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171 PackageParser.ServiceIntentInfo filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003172 out.print(prefix); out.print(
3173 Integer.toHexString(System.identityHashCode(filter.service)));
3174 out.print(' ');
3175 out.println(filter.service.componentShortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176 }
3177
3178// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
3179// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
3180// final List<ResolveInfo> retList = Lists.newArrayList();
3181// while (i.hasNext()) {
3182// final ResolveInfo resolveInfo = (ResolveInfo) i;
3183// if (isEnabledLP(resolveInfo.serviceInfo)) {
3184// retList.add(resolveInfo);
3185// }
3186// }
3187// return retList;
3188// }
3189
3190 // Keys are String (activity class name), values are Activity.
3191 private final HashMap<ComponentName, PackageParser.Service> mServices
3192 = new HashMap<ComponentName, PackageParser.Service>();
3193 private int mFlags;
3194 };
3195
3196 private static final Comparator<ResolveInfo> mResolvePrioritySorter =
3197 new Comparator<ResolveInfo>() {
3198 public int compare(ResolveInfo r1, ResolveInfo r2) {
3199 int v1 = r1.priority;
3200 int v2 = r2.priority;
3201 //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
3202 if (v1 != v2) {
3203 return (v1 > v2) ? -1 : 1;
3204 }
3205 v1 = r1.preferredOrder;
3206 v2 = r2.preferredOrder;
3207 if (v1 != v2) {
3208 return (v1 > v2) ? -1 : 1;
3209 }
3210 if (r1.isDefault != r2.isDefault) {
3211 return r1.isDefault ? -1 : 1;
3212 }
3213 v1 = r1.match;
3214 v2 = r2.match;
3215 //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
3216 return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
3217 }
3218 };
3219
3220 private static final Comparator<ProviderInfo> mProviderInitOrderSorter =
3221 new Comparator<ProviderInfo>() {
3222 public int compare(ProviderInfo p1, ProviderInfo p2) {
3223 final int v1 = p1.initOrder;
3224 final int v2 = p2.initOrder;
3225 return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
3226 }
3227 };
3228
3229 private static final void sendPackageBroadcast(String action, String pkg, Bundle extras) {
3230 IActivityManager am = ActivityManagerNative.getDefault();
3231 if (am != null) {
3232 try {
3233 final Intent intent = new Intent(action,
3234 pkg != null ? Uri.fromParts("package", pkg, null) : null);
3235 if (extras != null) {
3236 intent.putExtras(extras);
3237 }
3238 am.broadcastIntent(
3239 null, intent,
3240 null, null, 0, null, null, null, false, false);
3241 } catch (RemoteException ex) {
3242 }
3243 }
3244 }
3245
3246 private final class AppDirObserver extends FileObserver {
3247 public AppDirObserver(String path, int mask, boolean isrom) {
3248 super(path, mask);
3249 mRootDir = path;
3250 mIsRom = isrom;
3251 }
3252
3253 public void onEvent(int event, String path) {
3254 String removedPackage = null;
3255 int removedUid = -1;
3256 String addedPackage = null;
3257 int addedUid = -1;
3258
3259 synchronized (mInstallLock) {
3260 String fullPathStr = null;
3261 File fullPath = null;
3262 if (path != null) {
3263 fullPath = new File(mRootDir, path);
3264 fullPathStr = fullPath.getPath();
3265 }
3266
3267 if (Config.LOGV) Log.v(
3268 TAG, "File " + fullPathStr + " changed: "
3269 + Integer.toHexString(event));
3270
3271 if (!isPackageFilename(path)) {
3272 if (Config.LOGV) Log.v(
3273 TAG, "Ignoring change of non-package file: " + fullPathStr);
3274 return;
3275 }
3276
3277 if ((event&REMOVE_EVENTS) != 0) {
3278 synchronized (mInstallLock) {
3279 PackageParser.Package p = mAppDirs.get(fullPathStr);
3280 if (p != null) {
3281 removePackageLI(p, true);
3282 removedPackage = p.applicationInfo.packageName;
3283 removedUid = p.applicationInfo.uid;
3284 }
3285 }
3286 }
3287
3288 if ((event&ADD_EVENTS) != 0) {
3289 PackageParser.Package p = mAppDirs.get(fullPathStr);
3290 if (p == null) {
3291 p = scanPackageLI(fullPath, fullPath, fullPath,
3292 (mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) |
3293 PackageParser.PARSE_CHATTY |
3294 PackageParser.PARSE_MUST_BE_APK,
3295 SCAN_MONITOR);
3296 if (p != null) {
3297 synchronized (mPackages) {
3298 grantPermissionsLP(p, false);
3299 }
3300 addedPackage = p.applicationInfo.packageName;
3301 addedUid = p.applicationInfo.uid;
3302 }
3303 }
3304 }
3305
3306 synchronized (mPackages) {
3307 mSettings.writeLP();
3308 }
3309 }
3310
3311 if (removedPackage != null) {
3312 Bundle extras = new Bundle(1);
3313 extras.putInt(Intent.EXTRA_UID, removedUid);
3314 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
3315 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
3316 }
3317 if (addedPackage != null) {
3318 Bundle extras = new Bundle(1);
3319 extras.putInt(Intent.EXTRA_UID, addedUid);
3320 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras);
3321 }
3322 }
3323
3324 private final String mRootDir;
3325 private final boolean mIsRom;
3326 }
Jacek Surazskic64322c2009-04-28 15:26:38 +02003327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 /* Called when a downloaded package installation has been confirmed by the user */
3329 public void installPackage(
3330 final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
Jacek Surazskic64322c2009-04-28 15:26:38 +02003331 installPackage(packageURI, observer, flags, null);
3332 }
3333
3334 /* Called when a downloaded package installation has been confirmed by the user */
3335 public void installPackage(
3336 final Uri packageURI, final IPackageInstallObserver observer, final int flags,
3337 final String installerPackageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 mContext.enforceCallingOrSelfPermission(
3339 android.Manifest.permission.INSTALL_PACKAGES, null);
Jacek Surazskic64322c2009-04-28 15:26:38 +02003340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003341 // Queue up an async operation since the package installation may take a little while.
3342 mHandler.post(new Runnable() {
3343 public void run() {
3344 mHandler.removeCallbacks(this);
3345 PackageInstalledInfo res;
3346 synchronized (mInstallLock) {
Jacek Surazskic64322c2009-04-28 15:26:38 +02003347 res = installPackageLI(packageURI, flags, true, installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003348 }
3349 if (observer != null) {
3350 try {
3351 observer.packageInstalled(res.name, res.returnCode);
3352 } catch (RemoteException e) {
3353 Log.i(TAG, "Observer no longer exists.");
3354 }
3355 }
3356 // There appears to be a subtle deadlock condition if the sendPackageBroadcast
3357 // call appears in the synchronized block above.
3358 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
3359 res.removedInfo.sendBroadcast(false, true);
3360 Bundle extras = new Bundle(1);
3361 extras.putInt(Intent.EXTRA_UID, res.uid);
Dianne Hackbornf63220f2009-03-24 18:38:43 -07003362 final boolean update = res.removedInfo.removedPackage != null;
3363 if (update) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 extras.putBoolean(Intent.EXTRA_REPLACING, true);
3365 }
3366 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
3367 res.pkg.applicationInfo.packageName,
3368 extras);
Dianne Hackbornf63220f2009-03-24 18:38:43 -07003369 if (update) {
3370 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
3371 res.pkg.applicationInfo.packageName,
3372 extras);
3373 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 }
3375 Runtime.getRuntime().gc();
3376 }
3377 });
3378 }
3379
3380 class PackageInstalledInfo {
3381 String name;
3382 int uid;
3383 PackageParser.Package pkg;
3384 int returnCode;
3385 PackageRemovedInfo removedInfo;
3386 }
3387
3388 /*
3389 * Install a non-existing package.
3390 */
3391 private void installNewPackageLI(String pkgName,
3392 File tmpPackageFile,
3393 String destFilePath, File destPackageFile, File destResourceFile,
The Android Open Source Project10592532009-03-18 17:39:46 -07003394 PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003395 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 // Remember this for later, in case we need to rollback this install
3397 boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists();
3398 res.name = pkgName;
3399 synchronized(mPackages) {
3400 if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) {
3401 // Don't allow installation over an existing package with the same name.
3402 Log.w(TAG, "Attempt to re-install " + pkgName
3403 + " without first uninstalling.");
3404 res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
3405 return;
3406 }
3407 }
3408 if (destPackageFile.exists()) {
3409 // It's safe to do this because we know (from the above check) that the file
3410 // isn't currently used for an installed package.
3411 destPackageFile.delete();
3412 }
3413 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
3414 PackageParser.Package newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
3415 destResourceFile, pkg, 0,
3416 SCAN_MONITOR | SCAN_FORCE_DEX
3417 | SCAN_UPDATE_SIGNATURE
The Android Open Source Project10592532009-03-18 17:39:46 -07003418 | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
3419 | (newInstall ? SCAN_NEW_INSTALL : 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003420 if (newPackage == null) {
3421 Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
3422 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
3423 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
3424 }
3425 } else {
3426 updateSettingsLI(pkgName, tmpPackageFile,
3427 destFilePath, destPackageFile,
3428 destResourceFile, pkg,
3429 newPackage,
3430 true,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003431 forwardLocked,
3432 installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 res);
3434 // delete the partially installed application. the data directory will have to be
3435 // restored if it was already existing
3436 if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
3437 // remove package from internal structures. Note that we want deletePackageX to
3438 // delete the package data and cache directories that it created in
3439 // scanPackageLocked, unless those directories existed before we even tried to
3440 // install.
3441 deletePackageLI(
3442 pkgName, true,
3443 dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
3444 res.removedInfo);
3445 }
3446 }
3447 }
3448
3449 private void replacePackageLI(String pkgName,
3450 File tmpPackageFile,
3451 String destFilePath, File destPackageFile, File destResourceFile,
The Android Open Source Project10592532009-03-18 17:39:46 -07003452 PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003453 String installerPackageName, PackageInstalledInfo res) {
3454
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003455 PackageParser.Package oldPackage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003456 // First find the old package info and check signatures
3457 synchronized(mPackages) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003458 oldPackage = mPackages.get(pkgName);
3459 if(checkSignaturesLP(pkg, oldPackage) != PackageManager.SIGNATURE_MATCH) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
3461 return;
3462 }
3463 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003464 boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003465 if(sysPkg) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003466 replaceSystemPackageLI(oldPackage,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003467 tmpPackageFile, destFilePath,
The Android Open Source Project10592532009-03-18 17:39:46 -07003468 destPackageFile, destResourceFile, pkg, forwardLocked,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003469 newInstall, installerPackageName, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003470 } else {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003471 replaceNonSystemPackageLI(oldPackage, tmpPackageFile, destFilePath,
The Android Open Source Project10592532009-03-18 17:39:46 -07003472 destPackageFile, destResourceFile, pkg, forwardLocked,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003473 newInstall, installerPackageName, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 }
3475 }
3476
3477 private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
3478 File tmpPackageFile,
3479 String destFilePath, File destPackageFile, File destResourceFile,
The Android Open Source Project10592532009-03-18 17:39:46 -07003480 PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003481 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003482 PackageParser.Package newPackage = null;
3483 String pkgName = deletedPackage.packageName;
3484 boolean deletedPkg = true;
3485 boolean updatedSettings = false;
Jacek Surazskic64322c2009-04-28 15:26:38 +02003486
3487 String oldInstallerPackageName = null;
3488 synchronized (mPackages) {
3489 oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
3490 }
3491
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003492 int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003493 // First delete the existing package while retaining the data directory
3494 if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
3495 res.removedInfo)) {
3496 // If the existing package was'nt successfully deleted
3497 res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
3498 deletedPkg = false;
3499 } else {
3500 // Successfully deleted the old package. Now proceed with re-installation
3501 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
3502 newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
3503 destResourceFile, pkg, parseFlags,
3504 SCAN_MONITOR | SCAN_FORCE_DEX
3505 | SCAN_UPDATE_SIGNATURE
The Android Open Source Project10592532009-03-18 17:39:46 -07003506 | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
3507 | (newInstall ? SCAN_NEW_INSTALL : 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003508 if (newPackage == null) {
3509 Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
3510 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
3511 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
3512 }
3513 } else {
3514 updateSettingsLI(pkgName, tmpPackageFile,
3515 destFilePath, destPackageFile,
3516 destResourceFile, pkg,
3517 newPackage,
3518 true,
3519 forwardLocked,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003520 installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 res);
3522 updatedSettings = true;
3523 }
3524 }
3525
3526 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
3527 // If we deleted an exisiting package, the old source and resource files that we
3528 // were keeping around in case we needed them (see below) can now be deleted
3529 final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo;
3530 final ApplicationInfo installedPackageAppInfo =
3531 newPackage.applicationInfo;
3532 if (!deletedPackageAppInfo.sourceDir
3533 .equals(installedPackageAppInfo.sourceDir)) {
3534 new File(deletedPackageAppInfo.sourceDir).delete();
3535 }
3536 if (!deletedPackageAppInfo.publicSourceDir
3537 .equals(installedPackageAppInfo.publicSourceDir)) {
3538 new File(deletedPackageAppInfo.publicSourceDir).delete();
3539 }
3540 //update signature on the new package setting
3541 //this should always succeed, since we checked the
3542 //signature earlier.
3543 synchronized(mPackages) {
3544 verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg,
3545 parseFlags, true);
3546 }
3547 } else {
3548 // remove package from internal structures. Note that we want deletePackageX to
3549 // delete the package data and cache directories that it created in
3550 // scanPackageLocked, unless those directories existed before we even tried to
3551 // install.
3552 if(updatedSettings) {
3553 deletePackageLI(
3554 pkgName, true,
3555 PackageManager.DONT_DELETE_DATA,
3556 res.removedInfo);
3557 }
3558 // Since we failed to install the new package we need to restore the old
3559 // package that we deleted.
3560 if(deletedPkg) {
3561 installPackageLI(
3562 Uri.fromFile(new File(deletedPackage.mPath)),
3563 isForwardLocked(deletedPackage)
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003564 ? PackageManager.INSTALL_FORWARD_LOCK
Jacek Surazskic64322c2009-04-28 15:26:38 +02003565 : 0, false, oldInstallerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566 }
3567 }
3568 }
3569
3570 private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
3571 File tmpPackageFile,
3572 String destFilePath, File destPackageFile, File destResourceFile,
The Android Open Source Project10592532009-03-18 17:39:46 -07003573 PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003574 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003575 PackageParser.Package newPackage = null;
3576 boolean updatedSettings = false;
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003577 int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING |
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 PackageParser.PARSE_IS_SYSTEM;
3579 String packageName = deletedPackage.packageName;
3580 res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
3581 if (packageName == null) {
3582 Log.w(TAG, "Attempt to delete null packageName.");
3583 return;
3584 }
3585 PackageParser.Package oldPkg;
3586 PackageSetting oldPkgSetting;
3587 synchronized (mPackages) {
3588 oldPkg = mPackages.get(packageName);
3589 oldPkgSetting = mSettings.mPackages.get(packageName);
3590 if((oldPkg == null) || (oldPkg.applicationInfo == null) ||
3591 (oldPkgSetting == null)) {
3592 Log.w(TAG, "Could'nt find package:"+packageName+" information");
3593 return;
3594 }
3595 }
3596 res.removedInfo.uid = oldPkg.applicationInfo.uid;
3597 res.removedInfo.removedPackage = packageName;
3598 // Remove existing system package
3599 removePackageLI(oldPkg, true);
3600 synchronized (mPackages) {
3601 res.removedInfo.removedUid = mSettings.disableSystemPackageLP(packageName);
3602 }
3603
3604 // Successfully disabled the old package. Now proceed with re-installation
3605 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
3606 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
3607 newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
3608 destResourceFile, pkg, parseFlags,
3609 SCAN_MONITOR | SCAN_FORCE_DEX
3610 | SCAN_UPDATE_SIGNATURE
The Android Open Source Project10592532009-03-18 17:39:46 -07003611 | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
3612 | (newInstall ? SCAN_NEW_INSTALL : 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613 if (newPackage == null) {
3614 Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
3615 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
3616 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
3617 }
3618 } else {
3619 updateSettingsLI(packageName, tmpPackageFile,
3620 destFilePath, destPackageFile,
3621 destResourceFile, pkg,
3622 newPackage,
3623 true,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003624 forwardLocked,
3625 installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003626 res);
3627 updatedSettings = true;
3628 }
3629
3630 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
3631 //update signature on the new package setting
3632 //this should always succeed, since we checked the
3633 //signature earlier.
3634 synchronized(mPackages) {
3635 verifySignaturesLP(mSettings.mPackages.get(packageName), pkg,
3636 parseFlags, true);
3637 }
3638 } else {
3639 // Re installation failed. Restore old information
3640 // Remove new pkg information
Dianne Hackborna96cbb42009-05-13 15:06:13 -07003641 if (newPackage != null) {
3642 removePackageLI(newPackage, true);
3643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003644 // Add back the old system package
3645 scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath,
3646 oldPkgSetting.resourcePath,
3647 oldPkg, parseFlags,
3648 SCAN_MONITOR
The Android Open Source Project10592532009-03-18 17:39:46 -07003649 | SCAN_UPDATE_SIGNATURE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 // Restore the old system information in Settings
3651 synchronized(mPackages) {
3652 if(updatedSettings) {
3653 mSettings.enableSystemPackageLP(packageName);
Jacek Surazskic64322c2009-04-28 15:26:38 +02003654 mSettings.setInstallerPackageName(packageName,
3655 oldPkgSetting.installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003656 }
3657 mSettings.writeLP();
3658 }
3659 }
3660 }
3661
3662 private void updateSettingsLI(String pkgName, File tmpPackageFile,
3663 String destFilePath, File destPackageFile,
3664 File destResourceFile,
3665 PackageParser.Package pkg,
3666 PackageParser.Package newPackage,
3667 boolean replacingExistingPackage,
3668 boolean forwardLocked,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003669 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003670 synchronized (mPackages) {
3671 //write settings. the installStatus will be incomplete at this stage.
3672 //note that the new package setting would have already been
3673 //added to mPackages. It hasn't been persisted yet.
3674 mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE);
3675 mSettings.writeLP();
3676 }
3677
3678 int retCode = 0;
3679 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
3680 retCode = mInstaller.movedex(tmpPackageFile.toString(),
3681 destPackageFile.toString());
3682 if (retCode != 0) {
3683 Log.e(TAG, "Couldn't rename dex file: " + destPackageFile);
3684 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3685 return;
3686 }
3687 }
3688 // XXX There are probably some big issues here: upon doing
3689 // the rename, we have reached the point of no return (the
3690 // original .apk is gone!), so we can't fail. Yet... we can.
3691 if (!tmpPackageFile.renameTo(destPackageFile)) {
3692 Log.e(TAG, "Couldn't move package file to: " + destPackageFile);
3693 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3694 } else {
3695 res.returnCode = setPermissionsLI(pkgName, newPackage, destFilePath,
3696 destResourceFile,
3697 forwardLocked);
3698 if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
3699 return;
3700 } else {
3701 Log.d(TAG, "New package installed in " + destPackageFile);
3702 }
3703 }
3704 if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
3705 if (mInstaller != null) {
3706 mInstaller.rmdex(tmpPackageFile.getPath());
3707 }
3708 }
3709
3710 synchronized (mPackages) {
3711 grantPermissionsLP(newPackage, true);
3712 res.name = pkgName;
3713 res.uid = newPackage.applicationInfo.uid;
3714 res.pkg = newPackage;
3715 mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
Jacek Surazskic64322c2009-04-28 15:26:38 +02003716 mSettings.setInstallerPackageName(pkgName, installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003717 res.returnCode = PackageManager.INSTALL_SUCCEEDED;
3718 //to update install status
3719 mSettings.writeLP();
3720 }
3721 }
3722
The Android Open Source Project10592532009-03-18 17:39:46 -07003723 private PackageInstalledInfo installPackageLI(Uri pPackageURI,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003724 int pFlags, boolean newInstall, String installerPackageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003725 File tmpPackageFile = null;
3726 String pkgName = null;
3727 boolean forwardLocked = false;
3728 boolean replacingExistingPackage = false;
3729 // Result object to be returned
3730 PackageInstalledInfo res = new PackageInstalledInfo();
3731 res.returnCode = PackageManager.INSTALL_SUCCEEDED;
3732 res.uid = -1;
3733 res.pkg = null;
3734 res.removedInfo = new PackageRemovedInfo();
3735
3736 main_flow: try {
3737 tmpPackageFile = createTempPackageFile();
3738 if (tmpPackageFile == null) {
3739 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3740 break main_flow;
3741 }
3742 tmpPackageFile.deleteOnExit(); // paranoia
3743 if (pPackageURI.getScheme().equals("file")) {
3744 final File srcPackageFile = new File(pPackageURI.getPath());
3745 // We copy the source package file to a temp file and then rename it to the
3746 // destination file in order to eliminate a window where the package directory
3747 // scanner notices the new package file but it's not completely copied yet.
3748 if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
3749 Log.e(TAG, "Couldn't copy package file to temp file.");
3750 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3751 break main_flow;
3752 }
3753 } else if (pPackageURI.getScheme().equals("content")) {
3754 ParcelFileDescriptor fd;
3755 try {
3756 fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
3757 } catch (FileNotFoundException e) {
3758 Log.e(TAG, "Couldn't open file descriptor from download service.");
3759 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3760 break main_flow;
3761 }
3762 if (fd == null) {
3763 Log.e(TAG, "Couldn't open file descriptor from download service (null).");
3764 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3765 break main_flow;
3766 }
3767 if (Config.LOGV) {
3768 Log.v(TAG, "Opened file descriptor from download service.");
3769 }
3770 ParcelFileDescriptor.AutoCloseInputStream
3771 dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd);
3772 // We copy the source package file to a temp file and then rename it to the
3773 // destination file in order to eliminate a window where the package directory
3774 // scanner notices the new package file but it's not completely copied yet.
3775 if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) {
3776 Log.e(TAG, "Couldn't copy package stream to temp file.");
3777 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3778 break main_flow;
3779 }
3780 } else {
3781 Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
3782 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI;
3783 break main_flow;
3784 }
3785 pkgName = PackageParser.parsePackageName(
3786 tmpPackageFile.getAbsolutePath(), 0);
3787 if (pkgName == null) {
3788 Log.e(TAG, "Couldn't find a package name in : " + tmpPackageFile);
3789 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
3790 break main_flow;
3791 }
3792 res.name = pkgName;
3793 //initialize some variables before installing pkg
3794 final String pkgFileName = pkgName + ".apk";
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003795 final File destDir = ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 ? mDrmAppPrivateInstallDir
3797 : mAppInstallDir;
3798 final File destPackageFile = new File(destDir, pkgFileName);
3799 final String destFilePath = destPackageFile.getAbsolutePath();
3800 File destResourceFile;
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003801 if ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003802 final String publicZipFileName = pkgName + ".zip";
3803 destResourceFile = new File(mAppInstallDir, publicZipFileName);
3804 forwardLocked = true;
3805 } else {
3806 destResourceFile = destPackageFile;
3807 }
3808 // Retrieve PackageSettings and parse package
3809 int parseFlags = PackageParser.PARSE_CHATTY;
3810 parseFlags |= mDefParseFlags;
3811 PackageParser pp = new PackageParser(tmpPackageFile.getPath());
3812 pp.setSeparateProcesses(mSeparateProcesses);
Dianne Hackborn851a5412009-05-08 12:06:44 -07003813 pp.setSdkVersion(mSdkVersion, mSdkCodename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003814 final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
3815 destPackageFile.getAbsolutePath(), mMetrics, parseFlags);
3816 if (pkg == null) {
3817 res.returnCode = pp.getParseError();
3818 break main_flow;
3819 }
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003820 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
3821 if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
3822 res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
3823 break main_flow;
3824 }
3825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003826 if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
3827 res.returnCode = pp.getParseError();
3828 break main_flow;
3829 }
3830
3831 synchronized (mPackages) {
3832 //check if installing already existing package
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003833 if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003834 && mPackages.containsKey(pkgName)) {
3835 replacingExistingPackage = true;
3836 }
3837 }
3838
3839 if(replacingExistingPackage) {
3840 replacePackageLI(pkgName,
3841 tmpPackageFile,
3842 destFilePath, destPackageFile, destResourceFile,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003843 pkg, forwardLocked, newInstall, installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003844 res);
3845 } else {
3846 installNewPackageLI(pkgName,
3847 tmpPackageFile,
3848 destFilePath, destPackageFile, destResourceFile,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003849 pkg, forwardLocked, newInstall, installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003850 res);
3851 }
3852 } finally {
3853 if (tmpPackageFile != null && tmpPackageFile.exists()) {
3854 tmpPackageFile.delete();
3855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003856 }
The Android Open Source Project10592532009-03-18 17:39:46 -07003857 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003858 }
3859
3860 private int setPermissionsLI(String pkgName,
3861 PackageParser.Package newPackage,
3862 String destFilePath,
3863 File destResourceFile,
3864 boolean forwardLocked) {
3865 int retCode;
3866 if (forwardLocked) {
3867 try {
3868 extractPublicFiles(newPackage, destResourceFile);
3869 } catch (IOException e) {
3870 Log.e(TAG, "Couldn't create a new zip file for the public parts of a" +
3871 " forward-locked app.");
3872 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3873 } finally {
3874 //TODO clean up the extracted public files
3875 }
3876 if (mInstaller != null) {
3877 retCode = mInstaller.setForwardLockPerm(pkgName,
3878 newPackage.applicationInfo.uid);
3879 } else {
3880 final int filePermissions =
3881 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
3882 retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1,
3883 newPackage.applicationInfo.uid);
3884 }
3885 } else {
3886 final int filePermissions =
3887 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
3888 |FileUtils.S_IROTH;
3889 retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1);
3890 }
3891 if (retCode != 0) {
3892 Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath
3893 + ". The return code was: " + retCode);
3894 }
3895 return PackageManager.INSTALL_SUCCEEDED;
3896 }
3897
3898 private boolean isForwardLocked(PackageParser.Package deletedPackage) {
3899 final ApplicationInfo applicationInfo = deletedPackage.applicationInfo;
3900 return applicationInfo.sourceDir.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath());
3901 }
3902
3903 private void extractPublicFiles(PackageParser.Package newPackage,
3904 File publicZipFile) throws IOException {
3905 final ZipOutputStream publicZipOutStream =
3906 new ZipOutputStream(new FileOutputStream(publicZipFile));
3907 final ZipFile privateZip = new ZipFile(newPackage.mPath);
3908
3909 // Copy manifest, resources.arsc and res directory to public zip
3910
3911 final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
3912 while (privateZipEntries.hasMoreElements()) {
3913 final ZipEntry zipEntry = privateZipEntries.nextElement();
3914 final String zipEntryName = zipEntry.getName();
3915 if ("AndroidManifest.xml".equals(zipEntryName)
3916 || "resources.arsc".equals(zipEntryName)
3917 || zipEntryName.startsWith("res/")) {
3918 try {
3919 copyZipEntry(zipEntry, privateZip, publicZipOutStream);
3920 } catch (IOException e) {
3921 try {
3922 publicZipOutStream.close();
3923 throw e;
3924 } finally {
3925 publicZipFile.delete();
3926 }
3927 }
3928 }
3929 }
3930
3931 publicZipOutStream.close();
3932 FileUtils.setPermissions(
3933 publicZipFile.getAbsolutePath(),
3934 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP|FileUtils.S_IROTH,
3935 -1, -1);
3936 }
3937
3938 private static void copyZipEntry(ZipEntry zipEntry,
3939 ZipFile inZipFile,
3940 ZipOutputStream outZipStream) throws IOException {
3941 byte[] buffer = new byte[4096];
3942 int num;
3943
3944 ZipEntry newEntry;
3945 if (zipEntry.getMethod() == ZipEntry.STORED) {
3946 // Preserve the STORED method of the input entry.
3947 newEntry = new ZipEntry(zipEntry);
3948 } else {
3949 // Create a new entry so that the compressed len is recomputed.
3950 newEntry = new ZipEntry(zipEntry.getName());
3951 }
3952 outZipStream.putNextEntry(newEntry);
3953
3954 InputStream data = inZipFile.getInputStream(zipEntry);
3955 while ((num = data.read(buffer)) > 0) {
3956 outZipStream.write(buffer, 0, num);
3957 }
3958 outZipStream.flush();
3959 }
3960
3961 private void deleteTempPackageFiles() {
3962 FilenameFilter filter = new FilenameFilter() {
3963 public boolean accept(File dir, String name) {
3964 return name.startsWith("vmdl") && name.endsWith(".tmp");
3965 }
3966 };
3967 String tmpFilesList[] = mAppInstallDir.list(filter);
3968 if(tmpFilesList == null) {
3969 return;
3970 }
3971 for(int i = 0; i < tmpFilesList.length; i++) {
3972 File tmpFile = new File(mAppInstallDir, tmpFilesList[i]);
3973 tmpFile.delete();
3974 }
3975 }
3976
3977 private File createTempPackageFile() {
3978 File tmpPackageFile;
3979 try {
3980 tmpPackageFile = File.createTempFile("vmdl", ".tmp", mAppInstallDir);
3981 } catch (IOException e) {
3982 Log.e(TAG, "Couldn't create temp file for downloaded package file.");
3983 return null;
3984 }
3985 try {
3986 FileUtils.setPermissions(
3987 tmpPackageFile.getCanonicalPath(), FileUtils.S_IRUSR|FileUtils.S_IWUSR,
3988 -1, -1);
3989 } catch (IOException e) {
3990 Log.e(TAG, "Trouble getting the canoncical path for a temp file.");
3991 return null;
3992 }
3993 return tmpPackageFile;
3994 }
3995
3996 public void deletePackage(final String packageName,
3997 final IPackageDeleteObserver observer,
3998 final int flags) {
3999 mContext.enforceCallingOrSelfPermission(
4000 android.Manifest.permission.DELETE_PACKAGES, null);
4001 // Queue up an async operation since the package deletion may take a little while.
4002 mHandler.post(new Runnable() {
4003 public void run() {
4004 mHandler.removeCallbacks(this);
4005 final boolean succeded = deletePackageX(packageName, true, true, flags);
4006 if (observer != null) {
4007 try {
4008 observer.packageDeleted(succeded);
4009 } catch (RemoteException e) {
4010 Log.i(TAG, "Observer no longer exists.");
4011 } //end catch
4012 } //end if
4013 } //end run
4014 });
4015 }
4016
4017 /**
4018 * This method is an internal method that could be get invoked either
4019 * to delete an installed package or to clean up a failed installation.
4020 * After deleting an installed package, a broadcast is sent to notify any
4021 * listeners that the package has been installed. For cleaning up a failed
4022 * installation, the broadcast is not necessary since the package's
4023 * installation wouldn't have sent the initial broadcast either
4024 * The key steps in deleting a package are
4025 * deleting the package information in internal structures like mPackages,
4026 * deleting the packages base directories through installd
4027 * updating mSettings to reflect current status
4028 * persisting settings for later use
4029 * sending a broadcast if necessary
4030 */
4031
4032 private boolean deletePackageX(String packageName, boolean sendBroadCast,
4033 boolean deleteCodeAndResources, int flags) {
4034 PackageRemovedInfo info = new PackageRemovedInfo();
Romain Guy96f43572009-03-24 20:27:49 -07004035 boolean res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004036
4037 synchronized (mInstallLock) {
4038 res = deletePackageLI(packageName, deleteCodeAndResources, flags, info);
4039 }
4040
4041 if(res && sendBroadCast) {
Romain Guy96f43572009-03-24 20:27:49 -07004042 boolean systemUpdate = info.isRemovedPackageSystemUpdate;
4043 info.sendBroadcast(deleteCodeAndResources, systemUpdate);
4044
4045 // If the removed package was a system update, the old system packaged
4046 // was re-enabled; we need to broadcast this information
4047 if (systemUpdate) {
4048 Bundle extras = new Bundle(1);
4049 extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
4050 extras.putBoolean(Intent.EXTRA_REPLACING, true);
4051
4052 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras);
4053 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras);
4054 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004055 }
4056 return res;
4057 }
4058
4059 static class PackageRemovedInfo {
4060 String removedPackage;
4061 int uid = -1;
4062 int removedUid = -1;
Romain Guy96f43572009-03-24 20:27:49 -07004063 boolean isRemovedPackageSystemUpdate = false;
4064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004065 void sendBroadcast(boolean fullRemove, boolean replacing) {
4066 Bundle extras = new Bundle(1);
4067 extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid);
4068 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
4069 if (replacing) {
4070 extras.putBoolean(Intent.EXTRA_REPLACING, true);
4071 }
4072 if (removedPackage != null) {
4073 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
4074 }
4075 if (removedUid >= 0) {
4076 sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras);
4077 }
4078 }
4079 }
4080
4081 /*
4082 * This method deletes the package from internal data structures. If the DONT_DELETE_DATA
4083 * flag is not set, the data directory is removed as well.
4084 * make sure this flag is set for partially installed apps. If not its meaningless to
4085 * delete a partially installed application.
4086 */
4087 private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
4088 int flags) {
4089 String packageName = p.packageName;
4090 outInfo.removedPackage = packageName;
4091 removePackageLI(p, true);
4092 // Retrieve object to delete permissions for shared user later on
4093 PackageSetting deletedPs;
4094 synchronized (mPackages) {
4095 deletedPs = mSettings.mPackages.get(packageName);
4096 }
4097 if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
4098 if (mInstaller != null) {
4099 int retCode = mInstaller.remove(packageName);
4100 if (retCode < 0) {
4101 Log.w(TAG, "Couldn't remove app data or cache directory for package: "
4102 + packageName + ", retcode=" + retCode);
4103 // we don't consider this to be a failure of the core package deletion
4104 }
4105 } else {
4106 //for emulator
4107 PackageParser.Package pkg = mPackages.get(packageName);
4108 File dataDir = new File(pkg.applicationInfo.dataDir);
4109 dataDir.delete();
4110 }
4111 synchronized (mPackages) {
4112 outInfo.removedUid = mSettings.removePackageLP(packageName);
4113 }
4114 }
4115 synchronized (mPackages) {
4116 if ( (deletedPs != null) && (deletedPs.sharedUser != null)) {
4117 // remove permissions associated with package
4118 mSettings.updateSharedUserPerms (deletedPs);
4119 }
4120 // Save settings now
4121 mSettings.writeLP ();
4122 }
4123 }
4124
4125 /*
4126 * Tries to delete system package.
4127 */
4128 private boolean deleteSystemPackageLI(PackageParser.Package p,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004129 int flags, PackageRemovedInfo outInfo) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004130 ApplicationInfo applicationInfo = p.applicationInfo;
4131 //applicable for non-partially installed applications only
4132 if (applicationInfo == null) {
4133 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
4134 return false;
4135 }
4136 PackageSetting ps = null;
4137 // Confirm if the system package has been updated
4138 // An updated system app can be deleted. This will also have to restore
4139 // the system pkg from system partition
4140 synchronized (mPackages) {
4141 ps = mSettings.getDisabledSystemPkg(p.packageName);
4142 }
4143 if (ps == null) {
4144 Log.w(TAG, "Attempt to delete system package "+ p.packageName);
4145 return false;
4146 } else {
4147 Log.i(TAG, "Deleting system pkg from data partition");
4148 }
4149 // Delete the updated package
Romain Guy96f43572009-03-24 20:27:49 -07004150 outInfo.isRemovedPackageSystemUpdate = true;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004151 boolean deleteCodeAndResources = false;
4152 if (ps.versionCode < p.mVersionCode) {
4153 // Delete code and resources for downgrades
4154 deleteCodeAndResources = true;
4155 if ((flags & PackageManager.DONT_DELETE_DATA) == 0) {
4156 flags &= ~PackageManager.DONT_DELETE_DATA;
4157 }
4158 } else {
4159 // Preserve data by setting flag
4160 if ((flags & PackageManager.DONT_DELETE_DATA) == 0) {
4161 flags |= PackageManager.DONT_DELETE_DATA;
4162 }
4163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004164 boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo);
4165 if (!ret) {
4166 return false;
4167 }
4168 synchronized (mPackages) {
4169 // Reinstate the old system package
4170 mSettings.enableSystemPackageLP(p.packageName);
4171 }
4172 // Install the system package
4173 PackageParser.Package newPkg = scanPackageLI(ps.codePath, ps.codePath, ps.resourcePath,
4174 PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
4175 SCAN_MONITOR);
4176
4177 if (newPkg == null) {
4178 Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
4179 return false;
4180 }
4181 synchronized (mPackages) {
Suchi Amalapurapu701f5162009-06-03 15:47:55 -07004182 grantPermissionsLP(newPkg, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004183 mSettings.writeLP();
4184 }
4185 return true;
4186 }
4187
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004188 private void deletePackageResourcesLI(String packageName,
4189 String sourceDir, String publicSourceDir) {
4190 File sourceFile = new File(sourceDir);
4191 if (!sourceFile.exists()) {
4192 Log.w(TAG, "Package source " + sourceDir + " does not exist.");
4193 }
4194 // Delete application's code and resources
4195 sourceFile.delete();
4196 final File publicSourceFile = new File(publicSourceDir);
4197 if (publicSourceFile.exists()) {
4198 publicSourceFile.delete();
4199 }
4200 if (mInstaller != null) {
4201 int retCode = mInstaller.rmdex(sourceFile.toString());
4202 if (retCode < 0) {
4203 Log.w(TAG, "Couldn't remove dex file for package: "
4204 + packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode);
4205 // we don't consider this to be a failure of the core package deletion
4206 }
4207 }
4208 }
4209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004210 private boolean deleteInstalledPackageLI(PackageParser.Package p,
4211 boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
4212 ApplicationInfo applicationInfo = p.applicationInfo;
4213 if (applicationInfo == null) {
4214 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
4215 return false;
4216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004217 outInfo.uid = applicationInfo.uid;
4218
4219 // Delete package data from internal structures and also remove data if flag is set
4220 removePackageDataLI(p, outInfo, flags);
4221
4222 // Delete application code and resources
4223 if (deleteCodeAndResources) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004224 deletePackageResourcesLI(applicationInfo.packageName,
4225 applicationInfo.sourceDir, applicationInfo.publicSourceDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004226 }
4227 return true;
4228 }
4229
4230 /*
4231 * This method handles package deletion in general
4232 */
4233 private boolean deletePackageLI(String packageName,
4234 boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
4235 if (packageName == null) {
4236 Log.w(TAG, "Attempt to delete null packageName.");
4237 return false;
4238 }
4239 PackageParser.Package p;
4240 boolean dataOnly = false;
4241 synchronized (mPackages) {
4242 p = mPackages.get(packageName);
4243 if (p == null) {
4244 //this retrieves partially installed apps
4245 dataOnly = true;
4246 PackageSetting ps = mSettings.mPackages.get(packageName);
4247 if (ps == null) {
4248 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4249 return false;
4250 }
4251 p = ps.pkg;
4252 }
4253 }
4254 if (p == null) {
4255 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4256 return false;
4257 }
4258
4259 if (dataOnly) {
4260 // Delete application data first
4261 removePackageDataLI(p, outInfo, flags);
4262 return true;
4263 }
4264 // At this point the package should have ApplicationInfo associated with it
4265 if (p.applicationInfo == null) {
4266 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
4267 return false;
4268 }
4269 if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
4270 Log.i(TAG, "Removing system package:"+p.packageName);
4271 // When an updated system application is deleted we delete the existing resources as well and
4272 // fall back to existing code in system partition
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004273 return deleteSystemPackageLI(p, flags, outInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004274 }
4275 Log.i(TAG, "Removing non-system package:"+p.packageName);
4276 return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
4277 }
4278
4279 public void clearApplicationUserData(final String packageName,
4280 final IPackageDataObserver observer) {
4281 mContext.enforceCallingOrSelfPermission(
4282 android.Manifest.permission.CLEAR_APP_USER_DATA, null);
4283 // Queue up an async operation since the package deletion may take a little while.
4284 mHandler.post(new Runnable() {
4285 public void run() {
4286 mHandler.removeCallbacks(this);
4287 final boolean succeeded;
4288 synchronized (mInstallLock) {
4289 succeeded = clearApplicationUserDataLI(packageName);
4290 }
4291 if (succeeded) {
4292 // invoke DeviceStorageMonitor's update method to clear any notifications
4293 DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
4294 ServiceManager.getService(DeviceStorageMonitorService.SERVICE);
4295 if (dsm != null) {
4296 dsm.updateMemory();
4297 }
4298 }
4299 if(observer != null) {
4300 try {
4301 observer.onRemoveCompleted(packageName, succeeded);
4302 } catch (RemoteException e) {
4303 Log.i(TAG, "Observer no longer exists.");
4304 }
4305 } //end if observer
4306 } //end run
4307 });
4308 }
4309
4310 private boolean clearApplicationUserDataLI(String packageName) {
4311 if (packageName == null) {
4312 Log.w(TAG, "Attempt to delete null packageName.");
4313 return false;
4314 }
4315 PackageParser.Package p;
4316 boolean dataOnly = false;
4317 synchronized (mPackages) {
4318 p = mPackages.get(packageName);
4319 if(p == null) {
4320 dataOnly = true;
4321 PackageSetting ps = mSettings.mPackages.get(packageName);
4322 if((ps == null) || (ps.pkg == null)) {
4323 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4324 return false;
4325 }
4326 p = ps.pkg;
4327 }
4328 }
4329 if(!dataOnly) {
4330 //need to check this only for fully installed applications
4331 if (p == null) {
4332 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4333 return false;
4334 }
4335 final ApplicationInfo applicationInfo = p.applicationInfo;
4336 if (applicationInfo == null) {
4337 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
4338 return false;
4339 }
4340 }
4341 if (mInstaller != null) {
4342 int retCode = mInstaller.clearUserData(packageName);
4343 if (retCode < 0) {
4344 Log.w(TAG, "Couldn't remove cache files for package: "
4345 + packageName);
4346 return false;
4347 }
4348 }
4349 return true;
4350 }
4351
4352 public void deleteApplicationCacheFiles(final String packageName,
4353 final IPackageDataObserver observer) {
4354 mContext.enforceCallingOrSelfPermission(
4355 android.Manifest.permission.DELETE_CACHE_FILES, null);
4356 // Queue up an async operation since the package deletion may take a little while.
4357 mHandler.post(new Runnable() {
4358 public void run() {
4359 mHandler.removeCallbacks(this);
4360 final boolean succeded;
4361 synchronized (mInstallLock) {
4362 succeded = deleteApplicationCacheFilesLI(packageName);
4363 }
4364 if(observer != null) {
4365 try {
4366 observer.onRemoveCompleted(packageName, succeded);
4367 } catch (RemoteException e) {
4368 Log.i(TAG, "Observer no longer exists.");
4369 }
4370 } //end if observer
4371 } //end run
4372 });
4373 }
4374
4375 private boolean deleteApplicationCacheFilesLI(String packageName) {
4376 if (packageName == null) {
4377 Log.w(TAG, "Attempt to delete null packageName.");
4378 return false;
4379 }
4380 PackageParser.Package p;
4381 synchronized (mPackages) {
4382 p = mPackages.get(packageName);
4383 }
4384 if (p == null) {
4385 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4386 return false;
4387 }
4388 final ApplicationInfo applicationInfo = p.applicationInfo;
4389 if (applicationInfo == null) {
4390 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
4391 return false;
4392 }
4393 if (mInstaller != null) {
4394 int retCode = mInstaller.deleteCacheFiles(packageName);
4395 if (retCode < 0) {
4396 Log.w(TAG, "Couldn't remove cache files for package: "
4397 + packageName);
4398 return false;
4399 }
4400 }
4401 return true;
4402 }
4403
4404 public void getPackageSizeInfo(final String packageName,
4405 final IPackageStatsObserver observer) {
4406 mContext.enforceCallingOrSelfPermission(
4407 android.Manifest.permission.GET_PACKAGE_SIZE, null);
4408 // Queue up an async operation since the package deletion may take a little while.
4409 mHandler.post(new Runnable() {
4410 public void run() {
4411 mHandler.removeCallbacks(this);
4412 PackageStats lStats = new PackageStats(packageName);
4413 final boolean succeded;
4414 synchronized (mInstallLock) {
4415 succeded = getPackageSizeInfoLI(packageName, lStats);
4416 }
4417 if(observer != null) {
4418 try {
4419 observer.onGetStatsCompleted(lStats, succeded);
4420 } catch (RemoteException e) {
4421 Log.i(TAG, "Observer no longer exists.");
4422 }
4423 } //end if observer
4424 } //end run
4425 });
4426 }
4427
4428 private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) {
4429 if (packageName == null) {
4430 Log.w(TAG, "Attempt to get size of null packageName.");
4431 return false;
4432 }
4433 PackageParser.Package p;
4434 boolean dataOnly = false;
4435 synchronized (mPackages) {
4436 p = mPackages.get(packageName);
4437 if(p == null) {
4438 dataOnly = true;
4439 PackageSetting ps = mSettings.mPackages.get(packageName);
4440 if((ps == null) || (ps.pkg == null)) {
4441 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4442 return false;
4443 }
4444 p = ps.pkg;
4445 }
4446 }
4447 String publicSrcDir = null;
4448 if(!dataOnly) {
4449 final ApplicationInfo applicationInfo = p.applicationInfo;
4450 if (applicationInfo == null) {
4451 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
4452 return false;
4453 }
4454 publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
4455 }
4456 if (mInstaller != null) {
4457 int res = mInstaller.getSizeInfo(packageName, p.mPath,
4458 publicSrcDir, pStats);
4459 if (res < 0) {
4460 return false;
4461 } else {
4462 return true;
4463 }
4464 }
4465 return true;
4466 }
4467
4468
4469 public void addPackageToPreferred(String packageName) {
4470 mContext.enforceCallingOrSelfPermission(
4471 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4472
4473 synchronized (mPackages) {
4474 PackageParser.Package p = mPackages.get(packageName);
4475 if (p == null) {
4476 return;
4477 }
4478 PackageSetting ps = (PackageSetting)p.mExtras;
4479 if (ps != null) {
4480 mSettings.mPreferredPackages.remove(ps);
4481 mSettings.mPreferredPackages.add(0, ps);
4482 updatePreferredIndicesLP();
4483 mSettings.writeLP();
4484 }
4485 }
4486 }
4487
4488 public void removePackageFromPreferred(String packageName) {
4489 mContext.enforceCallingOrSelfPermission(
4490 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4491
4492 synchronized (mPackages) {
4493 PackageParser.Package p = mPackages.get(packageName);
4494 if (p == null) {
4495 return;
4496 }
4497 if (p.mPreferredOrder > 0) {
4498 PackageSetting ps = (PackageSetting)p.mExtras;
4499 if (ps != null) {
4500 mSettings.mPreferredPackages.remove(ps);
4501 p.mPreferredOrder = 0;
4502 updatePreferredIndicesLP();
4503 mSettings.writeLP();
4504 }
4505 }
4506 }
4507 }
4508
4509 private void updatePreferredIndicesLP() {
4510 final ArrayList<PackageSetting> pkgs
4511 = mSettings.mPreferredPackages;
4512 final int N = pkgs.size();
4513 for (int i=0; i<N; i++) {
4514 pkgs.get(i).pkg.mPreferredOrder = N - i;
4515 }
4516 }
4517
4518 public List<PackageInfo> getPreferredPackages(int flags) {
4519 synchronized (mPackages) {
4520 final ArrayList<PackageInfo> res = new ArrayList<PackageInfo>();
4521 final ArrayList<PackageSetting> pref = mSettings.mPreferredPackages;
4522 final int N = pref.size();
4523 for (int i=0; i<N; i++) {
4524 res.add(generatePackageInfo(pref.get(i).pkg, flags));
4525 }
4526 return res;
4527 }
4528 }
4529
4530 public void addPreferredActivity(IntentFilter filter, int match,
4531 ComponentName[] set, ComponentName activity) {
4532 mContext.enforceCallingOrSelfPermission(
4533 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4534
4535 synchronized (mPackages) {
4536 Log.i(TAG, "Adding preferred activity " + activity + ":");
4537 filter.dump(new LogPrinter(Log.INFO, TAG), " ");
4538 mSettings.mPreferredActivities.addFilter(
4539 new PreferredActivity(filter, match, set, activity));
4540 mSettings.writeLP();
4541 }
4542 }
4543
Satish Sampath8dbe6122009-06-02 23:35:54 +01004544 public void replacePreferredActivity(IntentFilter filter, int match,
4545 ComponentName[] set, ComponentName activity) {
4546 mContext.enforceCallingOrSelfPermission(
4547 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4548 if (filter.countActions() != 1) {
4549 throw new IllegalArgumentException(
4550 "replacePreferredActivity expects filter to have only 1 action.");
4551 }
4552 if (filter.countCategories() != 1) {
4553 throw new IllegalArgumentException(
4554 "replacePreferredActivity expects filter to have only 1 category.");
4555 }
4556 if (filter.countDataAuthorities() != 0
4557 || filter.countDataPaths() != 0
4558 || filter.countDataSchemes() != 0
4559 || filter.countDataTypes() != 0) {
4560 throw new IllegalArgumentException(
4561 "replacePreferredActivity expects filter to have no data authorities, " +
4562 "paths, schemes or types.");
4563 }
4564 synchronized (mPackages) {
4565 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
4566 String action = filter.getAction(0);
4567 String category = filter.getCategory(0);
4568 while (it.hasNext()) {
4569 PreferredActivity pa = it.next();
4570 if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
4571 it.remove();
4572 Log.i(TAG, "Removed preferred activity " + pa.mActivity + ":");
4573 filter.dump(new LogPrinter(Log.INFO, TAG), " ");
4574 }
4575 }
4576 addPreferredActivity(filter, match, set, activity);
4577 }
4578 }
4579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004580 public void clearPackagePreferredActivities(String packageName) {
4581 mContext.enforceCallingOrSelfPermission(
4582 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4583
4584 synchronized (mPackages) {
4585 if (clearPackagePreferredActivitiesLP(packageName)) {
4586 mSettings.writeLP();
4587 }
4588 }
4589 }
4590
4591 boolean clearPackagePreferredActivitiesLP(String packageName) {
4592 boolean changed = false;
4593 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
4594 while (it.hasNext()) {
4595 PreferredActivity pa = it.next();
4596 if (pa.mActivity.getPackageName().equals(packageName)) {
4597 it.remove();
4598 changed = true;
4599 }
4600 }
4601 return changed;
4602 }
4603
4604 public int getPreferredActivities(List<IntentFilter> outFilters,
4605 List<ComponentName> outActivities, String packageName) {
4606
4607 int num = 0;
4608 synchronized (mPackages) {
4609 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
4610 while (it.hasNext()) {
4611 PreferredActivity pa = it.next();
4612 if (packageName == null
4613 || pa.mActivity.getPackageName().equals(packageName)) {
4614 if (outFilters != null) {
4615 outFilters.add(new IntentFilter(pa));
4616 }
4617 if (outActivities != null) {
4618 outActivities.add(pa.mActivity);
4619 }
4620 }
4621 }
4622 }
4623
4624 return num;
4625 }
4626
4627 public void setApplicationEnabledSetting(String appPackageName,
4628 int newState, int flags) {
4629 setEnabledSetting(appPackageName, null, newState, flags);
4630 }
4631
4632 public void setComponentEnabledSetting(ComponentName componentName,
4633 int newState, int flags) {
4634 setEnabledSetting(componentName.getPackageName(),
4635 componentName.getClassName(), newState, flags);
4636 }
4637
4638 private void setEnabledSetting(
4639 final String packageNameStr, String classNameStr, int newState, final int flags) {
4640 if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
4641 || newState == COMPONENT_ENABLED_STATE_ENABLED
4642 || newState == COMPONENT_ENABLED_STATE_DISABLED)) {
4643 throw new IllegalArgumentException("Invalid new component state: "
4644 + newState);
4645 }
4646 PackageSetting pkgSetting;
4647 final int uid = Binder.getCallingUid();
4648 final int permission = mContext.checkCallingPermission(
4649 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
4650 final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
4651 int packageUid = -1;
4652 synchronized (mPackages) {
4653 pkgSetting = mSettings.mPackages.get(packageNameStr);
4654 if (pkgSetting == null) {
4655 if (classNameStr == null) {
4656 throw new IllegalArgumentException(
4657 "Unknown package: " + packageNameStr);
4658 }
4659 throw new IllegalArgumentException(
4660 "Unknown component: " + packageNameStr
4661 + "/" + classNameStr);
4662 }
4663 if (!allowedByPermission && (uid != pkgSetting.userId)) {
4664 throw new SecurityException(
4665 "Permission Denial: attempt to change component state from pid="
4666 + Binder.getCallingPid()
4667 + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
4668 }
4669 packageUid = pkgSetting.userId;
4670 if (classNameStr == null) {
4671 // We're dealing with an application/package level state change
4672 pkgSetting.enabled = newState;
4673 } else {
4674 // We're dealing with a component level state change
4675 switch (newState) {
4676 case COMPONENT_ENABLED_STATE_ENABLED:
4677 pkgSetting.enableComponentLP(classNameStr);
4678 break;
4679 case COMPONENT_ENABLED_STATE_DISABLED:
4680 pkgSetting.disableComponentLP(classNameStr);
4681 break;
4682 case COMPONENT_ENABLED_STATE_DEFAULT:
4683 pkgSetting.restoreComponentLP(classNameStr);
4684 break;
4685 default:
4686 Log.e(TAG, "Invalid new component state: " + newState);
4687 }
4688 }
4689 mSettings.writeLP();
4690 }
4691
4692 long callingId = Binder.clearCallingIdentity();
4693 try {
4694 Bundle extras = new Bundle(2);
4695 extras.putBoolean(Intent.EXTRA_DONT_KILL_APP,
4696 (flags&PackageManager.DONT_KILL_APP) != 0);
4697 extras.putInt(Intent.EXTRA_UID, packageUid);
4698 sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageNameStr, extras);
4699 } finally {
4700 Binder.restoreCallingIdentity(callingId);
4701 }
4702 }
4703
Jacek Surazskic64322c2009-04-28 15:26:38 +02004704 public String getInstallerPackageName(String packageName) {
4705 synchronized (mPackages) {
4706 PackageSetting pkg = mSettings.mPackages.get(packageName);
4707 if (pkg == null) {
4708 throw new IllegalArgumentException("Unknown package: " + packageName);
4709 }
4710 return pkg.installerPackageName;
4711 }
4712 }
4713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004714 public int getApplicationEnabledSetting(String appPackageName) {
4715 synchronized (mPackages) {
4716 PackageSetting pkg = mSettings.mPackages.get(appPackageName);
4717 if (pkg == null) {
4718 throw new IllegalArgumentException("Unknown package: " + appPackageName);
4719 }
4720 return pkg.enabled;
4721 }
4722 }
4723
4724 public int getComponentEnabledSetting(ComponentName componentName) {
4725 synchronized (mPackages) {
4726 final String packageNameStr = componentName.getPackageName();
4727 PackageSetting pkg = mSettings.mPackages.get(packageNameStr);
4728 if (pkg == null) {
4729 throw new IllegalArgumentException("Unknown component: " + componentName);
4730 }
4731 final String classNameStr = componentName.getClassName();
4732 return pkg.currentEnabledStateLP(classNameStr);
4733 }
4734 }
4735
4736 public void enterSafeMode() {
4737 if (!mSystemReady) {
4738 mSafeMode = true;
4739 }
4740 }
4741
4742 public void systemReady() {
4743 mSystemReady = true;
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07004744
4745 // Read the compatibilty setting when the system is ready.
4746 mCompatibilityModeEnabled = android.provider.Settings.System.getInt(
4747 mContext.getContentResolver(),
4748 android.provider.Settings.System.COMPATIBILITY_MODE, 1) == 1;
4749 if (DEBUG_SETTINGS) {
4750 Log.d(TAG, "compatibility mode:" + mCompatibilityModeEnabled);
4751 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004752 }
4753
4754 public boolean isSafeMode() {
4755 return mSafeMode;
4756 }
4757
4758 public boolean hasSystemUidErrors() {
4759 return mHasSystemUidErrors;
4760 }
4761
4762 static String arrayToString(int[] array) {
4763 StringBuffer buf = new StringBuffer(128);
4764 buf.append('[');
4765 if (array != null) {
4766 for (int i=0; i<array.length; i++) {
4767 if (i > 0) buf.append(", ");
4768 buf.append(array[i]);
4769 }
4770 }
4771 buf.append(']');
4772 return buf.toString();
4773 }
4774
4775 @Override
4776 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4777 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
4778 != PackageManager.PERMISSION_GRANTED) {
4779 pw.println("Permission Denial: can't dump ActivityManager from from pid="
4780 + Binder.getCallingPid()
4781 + ", uid=" + Binder.getCallingUid()
4782 + " without permission "
4783 + android.Manifest.permission.DUMP);
4784 return;
4785 }
4786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004787 synchronized (mPackages) {
4788 pw.println("Activity Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004789 mActivities.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004790 pw.println(" ");
4791 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004792 mReceivers.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004793 pw.println(" ");
4794 pw.println("Service Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004795 mServices.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004796 pw.println(" ");
4797 pw.println("Preferred Activities:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004798 mSettings.mPreferredActivities.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004799 pw.println(" ");
4800 pw.println("Preferred Packages:");
4801 {
4802 for (PackageSetting ps : mSettings.mPreferredPackages) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004803 pw.print(" "); pw.println(ps.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004804 }
4805 }
4806 pw.println(" ");
4807 pw.println("Permissions:");
4808 {
4809 for (BasePermission p : mSettings.mPermissions.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004810 pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
4811 pw.print(Integer.toHexString(System.identityHashCode(p)));
4812 pw.println("):");
4813 pw.print(" sourcePackage="); pw.println(p.sourcePackage);
4814 pw.print(" uid="); pw.print(p.uid);
4815 pw.print(" gids="); pw.print(arrayToString(p.gids));
4816 pw.print(" type="); pw.println(p.type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004817 }
4818 }
4819 pw.println(" ");
4820 pw.println("Packages:");
4821 {
4822 for (PackageSetting ps : mSettings.mPackages.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004823 pw.print(" Package ["); pw.print(ps.name); pw.print("] (");
4824 pw.print(Integer.toHexString(System.identityHashCode(ps)));
4825 pw.println("):");
4826 pw.print(" userId="); pw.print(ps.userId);
4827 pw.print(" gids="); pw.println(arrayToString(ps.gids));
4828 pw.print(" sharedUser="); pw.println(ps.sharedUser);
4829 pw.print(" pkg="); pw.println(ps.pkg);
4830 pw.print(" codePath="); pw.println(ps.codePathString);
4831 pw.print(" resourcePath="); pw.println(ps.resourcePathString);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004832 if (ps.pkg != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004833 pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004834 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004835 pw.print(" timeStamp="); pw.println(ps.getTimeStampStr());
4836 pw.print(" signatures="); pw.println(ps.signatures);
4837 pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
4838 pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
4839 pw.print(" installStatus="); pw.print(ps.installStatus);
4840 pw.print(" enabled="); pw.println(ps.enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004841 if (ps.disabledComponents.size() > 0) {
4842 pw.println(" disabledComponents:");
4843 for (String s : ps.disabledComponents) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004844 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004845 }
4846 }
4847 if (ps.enabledComponents.size() > 0) {
4848 pw.println(" enabledComponents:");
4849 for (String s : ps.enabledComponents) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004850 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004851 }
4852 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004853 if (ps.grantedPermissions.size() > 0) {
4854 pw.println(" grantedPermissions:");
4855 for (String s : ps.grantedPermissions) {
4856 pw.print(" "); pw.println(s);
4857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004858 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004859 if (ps.loadedPermissions.size() > 0) {
4860 pw.println(" loadedPermissions:");
4861 for (String s : ps.loadedPermissions) {
4862 pw.print(" "); pw.println(s);
4863 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004864 }
4865 }
4866 }
4867 pw.println(" ");
4868 pw.println("Shared Users:");
4869 {
4870 for (SharedUserSetting su : mSettings.mSharedUsers.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004871 pw.print(" SharedUser ["); pw.print(su.name); pw.print("] (");
4872 pw.print(Integer.toHexString(System.identityHashCode(su)));
4873 pw.println("):");
4874 pw.print(" userId="); pw.print(su.userId);
4875 pw.print(" gids="); pw.println(arrayToString(su.gids));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004876 pw.println(" grantedPermissions:");
4877 for (String s : su.grantedPermissions) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004878 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004879 }
4880 pw.println(" loadedPermissions:");
4881 for (String s : su.loadedPermissions) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004882 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004883 }
4884 }
4885 }
4886 pw.println(" ");
4887 pw.println("Settings parse messages:");
4888 pw.println(mSettings.mReadMessages.toString());
4889 }
4890 }
4891
4892 static final class BasePermission {
4893 final static int TYPE_NORMAL = 0;
4894 final static int TYPE_BUILTIN = 1;
4895 final static int TYPE_DYNAMIC = 2;
4896
4897 final String name;
4898 final String sourcePackage;
4899 final int type;
4900 PackageParser.Permission perm;
4901 PermissionInfo pendingInfo;
4902 int uid;
4903 int[] gids;
4904
4905 BasePermission(String _name, String _sourcePackage, int _type) {
4906 name = _name;
4907 sourcePackage = _sourcePackage;
4908 type = _type;
4909 }
4910 }
4911
4912 static class PackageSignatures {
4913 private Signature[] mSignatures;
4914
4915 PackageSignatures(Signature[] sigs) {
4916 assignSignatures(sigs);
4917 }
4918
4919 PackageSignatures() {
4920 }
4921
4922 void writeXml(XmlSerializer serializer, String tagName,
4923 ArrayList<Signature> pastSignatures) throws IOException {
4924 if (mSignatures == null) {
4925 return;
4926 }
4927 serializer.startTag(null, tagName);
4928 serializer.attribute(null, "count",
4929 Integer.toString(mSignatures.length));
4930 for (int i=0; i<mSignatures.length; i++) {
4931 serializer.startTag(null, "cert");
4932 final Signature sig = mSignatures[i];
4933 final int sigHash = sig.hashCode();
4934 final int numPast = pastSignatures.size();
4935 int j;
4936 for (j=0; j<numPast; j++) {
4937 Signature pastSig = pastSignatures.get(j);
4938 if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
4939 serializer.attribute(null, "index", Integer.toString(j));
4940 break;
4941 }
4942 }
4943 if (j >= numPast) {
4944 pastSignatures.add(sig);
4945 serializer.attribute(null, "index", Integer.toString(numPast));
4946 serializer.attribute(null, "key", sig.toCharsString());
4947 }
4948 serializer.endTag(null, "cert");
4949 }
4950 serializer.endTag(null, tagName);
4951 }
4952
4953 void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
4954 throws IOException, XmlPullParserException {
4955 String countStr = parser.getAttributeValue(null, "count");
4956 if (countStr == null) {
4957 reportSettingsProblem(Log.WARN,
4958 "Error in package manager settings: <signatures> has"
4959 + " no count at " + parser.getPositionDescription());
4960 XmlUtils.skipCurrentTag(parser);
4961 }
4962 final int count = Integer.parseInt(countStr);
4963 mSignatures = new Signature[count];
4964 int pos = 0;
4965
4966 int outerDepth = parser.getDepth();
4967 int type;
4968 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4969 && (type != XmlPullParser.END_TAG
4970 || parser.getDepth() > outerDepth)) {
4971 if (type == XmlPullParser.END_TAG
4972 || type == XmlPullParser.TEXT) {
4973 continue;
4974 }
4975
4976 String tagName = parser.getName();
4977 if (tagName.equals("cert")) {
4978 if (pos < count) {
4979 String index = parser.getAttributeValue(null, "index");
4980 if (index != null) {
4981 try {
4982 int idx = Integer.parseInt(index);
4983 String key = parser.getAttributeValue(null, "key");
4984 if (key == null) {
4985 if (idx >= 0 && idx < pastSignatures.size()) {
4986 Signature sig = pastSignatures.get(idx);
4987 if (sig != null) {
4988 mSignatures[pos] = pastSignatures.get(idx);
4989 pos++;
4990 } else {
4991 reportSettingsProblem(Log.WARN,
4992 "Error in package manager settings: <cert> "
4993 + "index " + index + " is not defined at "
4994 + parser.getPositionDescription());
4995 }
4996 } else {
4997 reportSettingsProblem(Log.WARN,
4998 "Error in package manager settings: <cert> "
4999 + "index " + index + " is out of bounds at "
5000 + parser.getPositionDescription());
5001 }
5002 } else {
5003 while (pastSignatures.size() <= idx) {
5004 pastSignatures.add(null);
5005 }
5006 Signature sig = new Signature(key);
5007 pastSignatures.set(idx, sig);
5008 mSignatures[pos] = sig;
5009 pos++;
5010 }
5011 } catch (NumberFormatException e) {
5012 reportSettingsProblem(Log.WARN,
5013 "Error in package manager settings: <cert> "
5014 + "index " + index + " is not a number at "
5015 + parser.getPositionDescription());
5016 }
5017 } else {
5018 reportSettingsProblem(Log.WARN,
5019 "Error in package manager settings: <cert> has"
5020 + " no index at " + parser.getPositionDescription());
5021 }
5022 } else {
5023 reportSettingsProblem(Log.WARN,
5024 "Error in package manager settings: too "
5025 + "many <cert> tags, expected " + count
5026 + " at " + parser.getPositionDescription());
5027 }
5028 } else {
5029 reportSettingsProblem(Log.WARN,
5030 "Unknown element under <cert>: "
5031 + parser.getName());
5032 }
5033 XmlUtils.skipCurrentTag(parser);
5034 }
5035
5036 if (pos < count) {
5037 // Should never happen -- there is an error in the written
5038 // settings -- but if it does we don't want to generate
5039 // a bad array.
5040 Signature[] newSigs = new Signature[pos];
5041 System.arraycopy(mSignatures, 0, newSigs, 0, pos);
5042 mSignatures = newSigs;
5043 }
5044 }
5045
5046 /**
5047 * If any of the given 'sigs' is contained in the existing signatures,
5048 * then completely replace the current signatures with the ones in
5049 * 'sigs'. This is used for updating an existing package to a newly
5050 * installed version.
5051 */
5052 boolean updateSignatures(Signature[] sigs, boolean update) {
5053 if (mSignatures == null) {
5054 if (update) {
5055 assignSignatures(sigs);
5056 }
5057 return true;
5058 }
5059 if (sigs == null) {
5060 return false;
5061 }
5062
5063 for (int i=0; i<sigs.length; i++) {
5064 Signature sig = sigs[i];
5065 for (int j=0; j<mSignatures.length; j++) {
5066 if (mSignatures[j].equals(sig)) {
5067 if (update) {
5068 assignSignatures(sigs);
5069 }
5070 return true;
5071 }
5072 }
5073 }
5074 return false;
5075 }
5076
5077 /**
5078 * If any of the given 'sigs' is contained in the existing signatures,
5079 * then add in any new signatures found in 'sigs'. This is used for
5080 * including a new package into an existing shared user id.
5081 */
5082 boolean mergeSignatures(Signature[] sigs, boolean update) {
5083 if (mSignatures == null) {
5084 if (update) {
5085 assignSignatures(sigs);
5086 }
5087 return true;
5088 }
5089 if (sigs == null) {
5090 return false;
5091 }
5092
5093 Signature[] added = null;
5094 int addedCount = 0;
5095 boolean haveMatch = false;
5096 for (int i=0; i<sigs.length; i++) {
5097 Signature sig = sigs[i];
5098 boolean found = false;
5099 for (int j=0; j<mSignatures.length; j++) {
5100 if (mSignatures[j].equals(sig)) {
5101 found = true;
5102 haveMatch = true;
5103 break;
5104 }
5105 }
5106
5107 if (!found) {
5108 if (added == null) {
5109 added = new Signature[sigs.length];
5110 }
5111 added[i] = sig;
5112 addedCount++;
5113 }
5114 }
5115
5116 if (!haveMatch) {
5117 // Nothing matched -- reject the new signatures.
5118 return false;
5119 }
5120 if (added == null) {
5121 // Completely matched -- nothing else to do.
5122 return true;
5123 }
5124
5125 // Add additional signatures in.
5126 if (update) {
5127 Signature[] total = new Signature[addedCount+mSignatures.length];
5128 System.arraycopy(mSignatures, 0, total, 0, mSignatures.length);
5129 int j = mSignatures.length;
5130 for (int i=0; i<added.length; i++) {
5131 if (added[i] != null) {
5132 total[j] = added[i];
5133 j++;
5134 }
5135 }
5136 mSignatures = total;
5137 }
5138 return true;
5139 }
5140
5141 private void assignSignatures(Signature[] sigs) {
5142 if (sigs == null) {
5143 mSignatures = null;
5144 return;
5145 }
5146 mSignatures = new Signature[sigs.length];
5147 for (int i=0; i<sigs.length; i++) {
5148 mSignatures[i] = sigs[i];
5149 }
5150 }
5151
5152 @Override
5153 public String toString() {
5154 StringBuffer buf = new StringBuffer(128);
5155 buf.append("PackageSignatures{");
5156 buf.append(Integer.toHexString(System.identityHashCode(this)));
5157 buf.append(" [");
5158 if (mSignatures != null) {
5159 for (int i=0; i<mSignatures.length; i++) {
5160 if (i > 0) buf.append(", ");
5161 buf.append(Integer.toHexString(
5162 System.identityHashCode(mSignatures[i])));
5163 }
5164 }
5165 buf.append("]}");
5166 return buf.toString();
5167 }
5168 }
5169
5170 static class PreferredActivity extends IntentFilter {
5171 final int mMatch;
5172 final String[] mSetPackages;
5173 final String[] mSetClasses;
5174 final String[] mSetComponents;
5175 final ComponentName mActivity;
5176 final String mShortActivity;
5177 String mParseError;
5178
5179 PreferredActivity(IntentFilter filter, int match, ComponentName[] set,
5180 ComponentName activity) {
5181 super(filter);
5182 mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
5183 mActivity = activity;
5184 mShortActivity = activity.flattenToShortString();
5185 mParseError = null;
5186 if (set != null) {
5187 final int N = set.length;
5188 String[] myPackages = new String[N];
5189 String[] myClasses = new String[N];
5190 String[] myComponents = new String[N];
5191 for (int i=0; i<N; i++) {
5192 ComponentName cn = set[i];
5193 if (cn == null) {
5194 mSetPackages = null;
5195 mSetClasses = null;
5196 mSetComponents = null;
5197 return;
5198 }
5199 myPackages[i] = cn.getPackageName().intern();
5200 myClasses[i] = cn.getClassName().intern();
5201 myComponents[i] = cn.flattenToShortString().intern();
5202 }
5203 mSetPackages = myPackages;
5204 mSetClasses = myClasses;
5205 mSetComponents = myComponents;
5206 } else {
5207 mSetPackages = null;
5208 mSetClasses = null;
5209 mSetComponents = null;
5210 }
5211 }
5212
5213 PreferredActivity(XmlPullParser parser) throws XmlPullParserException,
5214 IOException {
5215 mShortActivity = parser.getAttributeValue(null, "name");
5216 mActivity = ComponentName.unflattenFromString(mShortActivity);
5217 if (mActivity == null) {
5218 mParseError = "Bad activity name " + mShortActivity;
5219 }
5220 String matchStr = parser.getAttributeValue(null, "match");
5221 mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
5222 String setCountStr = parser.getAttributeValue(null, "set");
5223 int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
5224
5225 String[] myPackages = setCount > 0 ? new String[setCount] : null;
5226 String[] myClasses = setCount > 0 ? new String[setCount] : null;
5227 String[] myComponents = setCount > 0 ? new String[setCount] : null;
5228
5229 int setPos = 0;
5230
5231 int outerDepth = parser.getDepth();
5232 int type;
5233 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
5234 && (type != XmlPullParser.END_TAG
5235 || parser.getDepth() > outerDepth)) {
5236 if (type == XmlPullParser.END_TAG
5237 || type == XmlPullParser.TEXT) {
5238 continue;
5239 }
5240
5241 String tagName = parser.getName();
5242 //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth="
5243 // + parser.getDepth() + " tag=" + tagName);
5244 if (tagName.equals("set")) {
5245 String name = parser.getAttributeValue(null, "name");
5246 if (name == null) {
5247 if (mParseError == null) {
5248 mParseError = "No name in set tag in preferred activity "
5249 + mShortActivity;
5250 }
5251 } else if (setPos >= setCount) {
5252 if (mParseError == null) {
5253 mParseError = "Too many set tags in preferred activity "
5254 + mShortActivity;
5255 }
5256 } else {
5257 ComponentName cn = ComponentName.unflattenFromString(name);
5258 if (cn == null) {
5259 if (mParseError == null) {
5260 mParseError = "Bad set name " + name + " in preferred activity "
5261 + mShortActivity;
5262 }
5263 } else {
5264 myPackages[setPos] = cn.getPackageName();
5265 myClasses[setPos] = cn.getClassName();
5266 myComponents[setPos] = name;
5267 setPos++;
5268 }
5269 }
5270 XmlUtils.skipCurrentTag(parser);
5271 } else if (tagName.equals("filter")) {
5272 //Log.i(TAG, "Starting to parse filter...");
5273 readFromXml(parser);
5274 //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth="
5275 // + parser.getDepth() + " tag=" + parser.getName());
5276 } else {
5277 reportSettingsProblem(Log.WARN,
5278 "Unknown element under <preferred-activities>: "
5279 + parser.getName());
5280 XmlUtils.skipCurrentTag(parser);
5281 }
5282 }
5283
5284 if (setPos != setCount) {
5285 if (mParseError == null) {
5286 mParseError = "Not enough set tags (expected " + setCount
5287 + " but found " + setPos + ") in " + mShortActivity;
5288 }
5289 }
5290
5291 mSetPackages = myPackages;
5292 mSetClasses = myClasses;
5293 mSetComponents = myComponents;
5294 }
5295
5296 public void writeToXml(XmlSerializer serializer) throws IOException {
5297 final int NS = mSetClasses != null ? mSetClasses.length : 0;
5298 serializer.attribute(null, "name", mShortActivity);
5299 serializer.attribute(null, "match", Integer.toHexString(mMatch));
5300 serializer.attribute(null, "set", Integer.toString(NS));
5301 for (int s=0; s<NS; s++) {
5302 serializer.startTag(null, "set");
5303 serializer.attribute(null, "name", mSetComponents[s]);
5304 serializer.endTag(null, "set");
5305 }
5306 serializer.startTag(null, "filter");
5307 super.writeToXml(serializer);
5308 serializer.endTag(null, "filter");
5309 }
5310
5311 boolean sameSet(List<ResolveInfo> query, int priority) {
5312 if (mSetPackages == null) return false;
5313 final int NQ = query.size();
5314 final int NS = mSetPackages.length;
5315 int numMatch = 0;
5316 for (int i=0; i<NQ; i++) {
5317 ResolveInfo ri = query.get(i);
5318 if (ri.priority != priority) continue;
5319 ActivityInfo ai = ri.activityInfo;
5320 boolean good = false;
5321 for (int j=0; j<NS; j++) {
5322 if (mSetPackages[j].equals(ai.packageName)
5323 && mSetClasses[j].equals(ai.name)) {
5324 numMatch++;
5325 good = true;
5326 break;
5327 }
5328 }
5329 if (!good) return false;
5330 }
5331 return numMatch == NS;
5332 }
5333 }
5334
5335 static class GrantedPermissions {
5336 final int pkgFlags;
5337
5338 HashSet<String> grantedPermissions = new HashSet<String>();
5339 int[] gids;
5340
5341 HashSet<String> loadedPermissions = new HashSet<String>();
5342
5343 GrantedPermissions(int pkgFlags) {
5344 this.pkgFlags = pkgFlags & ApplicationInfo.FLAG_SYSTEM;
5345 }
5346 }
5347
5348 /**
5349 * Settings base class for pending and resolved classes.
5350 */
5351 static class PackageSettingBase extends GrantedPermissions {
5352 final String name;
5353 final File codePath;
5354 final String codePathString;
5355 final File resourcePath;
5356 final String resourcePathString;
5357 private long timeStamp;
5358 private String timeStampString = "0";
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005359 final int versionCode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005360
5361 PackageSignatures signatures = new PackageSignatures();
5362
5363 boolean permissionsFixed;
5364
5365 /* Explicitly disabled components */
5366 HashSet<String> disabledComponents = new HashSet<String>(0);
5367 /* Explicitly enabled components */
5368 HashSet<String> enabledComponents = new HashSet<String>(0);
5369 int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
5370 int installStatus = PKG_INSTALL_COMPLETE;
Jacek Surazskic64322c2009-04-28 15:26:38 +02005371
5372 /* package name of the app that installed this package */
5373 String installerPackageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005374
5375 PackageSettingBase(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005376 int pVersionCode, int pkgFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005377 super(pkgFlags);
5378 this.name = name;
5379 this.codePath = codePath;
5380 this.codePathString = codePath.toString();
5381 this.resourcePath = resourcePath;
5382 this.resourcePathString = resourcePath.toString();
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005383 this.versionCode = pVersionCode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005384 }
5385
Jacek Surazskic64322c2009-04-28 15:26:38 +02005386 public void setInstallerPackageName(String packageName) {
5387 installerPackageName = packageName;
5388 }
5389
5390 String getInstallerPackageName() {
5391 return installerPackageName;
5392 }
5393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394 public void setInstallStatus(int newStatus) {
5395 installStatus = newStatus;
5396 }
5397
5398 public int getInstallStatus() {
5399 return installStatus;
5400 }
5401
5402 public void setTimeStamp(long newStamp) {
5403 if (newStamp != timeStamp) {
5404 timeStamp = newStamp;
5405 timeStampString = Long.toString(newStamp);
5406 }
5407 }
5408
5409 public void setTimeStamp(long newStamp, String newStampStr) {
5410 timeStamp = newStamp;
5411 timeStampString = newStampStr;
5412 }
5413
5414 public long getTimeStamp() {
5415 return timeStamp;
5416 }
5417
5418 public String getTimeStampStr() {
5419 return timeStampString;
5420 }
5421
5422 public void copyFrom(PackageSettingBase base) {
5423 grantedPermissions = base.grantedPermissions;
5424 gids = base.gids;
5425 loadedPermissions = base.loadedPermissions;
5426
5427 timeStamp = base.timeStamp;
5428 timeStampString = base.timeStampString;
5429 signatures = base.signatures;
5430 permissionsFixed = base.permissionsFixed;
5431 disabledComponents = base.disabledComponents;
5432 enabledComponents = base.enabledComponents;
5433 enabled = base.enabled;
5434 installStatus = base.installStatus;
5435 }
5436
5437 void enableComponentLP(String componentClassName) {
5438 disabledComponents.remove(componentClassName);
5439 enabledComponents.add(componentClassName);
5440 }
5441
5442 void disableComponentLP(String componentClassName) {
5443 enabledComponents.remove(componentClassName);
5444 disabledComponents.add(componentClassName);
5445 }
5446
5447 void restoreComponentLP(String componentClassName) {
5448 enabledComponents.remove(componentClassName);
5449 disabledComponents.remove(componentClassName);
5450 }
5451
5452 int currentEnabledStateLP(String componentName) {
5453 if (enabledComponents.contains(componentName)) {
5454 return COMPONENT_ENABLED_STATE_ENABLED;
5455 } else if (disabledComponents.contains(componentName)) {
5456 return COMPONENT_ENABLED_STATE_DISABLED;
5457 } else {
5458 return COMPONENT_ENABLED_STATE_DEFAULT;
5459 }
5460 }
5461 }
5462
5463 /**
5464 * Settings data for a particular package we know about.
5465 */
5466 static final class PackageSetting extends PackageSettingBase {
5467 int userId;
5468 PackageParser.Package pkg;
5469 SharedUserSetting sharedUser;
5470
5471 PackageSetting(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005472 int pVersionCode, int pkgFlags) {
5473 super(name, codePath, resourcePath, pVersionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005474 }
5475
5476 @Override
5477 public String toString() {
5478 return "PackageSetting{"
5479 + Integer.toHexString(System.identityHashCode(this))
5480 + " " + name + "/" + userId + "}";
5481 }
5482 }
5483
5484 /**
5485 * Settings data for a particular shared user ID we know about.
5486 */
5487 static final class SharedUserSetting extends GrantedPermissions {
5488 final String name;
5489 int userId;
5490 final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
5491 final PackageSignatures signatures = new PackageSignatures();
5492
5493 SharedUserSetting(String _name, int _pkgFlags) {
5494 super(_pkgFlags);
5495 name = _name;
5496 }
5497
5498 @Override
5499 public String toString() {
5500 return "SharedUserSetting{"
5501 + Integer.toHexString(System.identityHashCode(this))
5502 + " " + name + "/" + userId + "}";
5503 }
5504 }
5505
5506 /**
5507 * Holds information about dynamic settings.
5508 */
5509 private static final class Settings {
5510 private final File mSettingsFilename;
5511 private final File mBackupSettingsFilename;
5512 private final HashMap<String, PackageSetting> mPackages =
5513 new HashMap<String, PackageSetting>();
5514 // The user's preferred packages/applications, in order of preference.
5515 // First is the most preferred.
5516 private final ArrayList<PackageSetting> mPreferredPackages =
5517 new ArrayList<PackageSetting>();
5518 // List of replaced system applications
5519 final HashMap<String, PackageSetting> mDisabledSysPackages =
5520 new HashMap<String, PackageSetting>();
5521
5522 // The user's preferred activities associated with particular intent
5523 // filters.
5524 private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
5525 new IntentResolver<PreferredActivity, PreferredActivity>() {
5526 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005527 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005528 PreferredActivity filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005529 out.print(prefix); out.print(
5530 Integer.toHexString(System.identityHashCode(filter)));
5531 out.print(' ');
5532 out.print(filter.mActivity.flattenToShortString());
5533 out.print(" match=0x");
5534 out.println( Integer.toHexString(filter.mMatch));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005535 if (filter.mSetComponents != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005536 out.print(prefix); out.println(" Selected from:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005537 for (int i=0; i<filter.mSetComponents.length; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005538 out.print(prefix); out.print(" ");
5539 out.println(filter.mSetComponents[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005540 }
5541 }
5542 }
5543 };
5544 private final HashMap<String, SharedUserSetting> mSharedUsers =
5545 new HashMap<String, SharedUserSetting>();
5546 private final ArrayList<Object> mUserIds = new ArrayList<Object>();
5547 private final SparseArray<Object> mOtherUserIds =
5548 new SparseArray<Object>();
5549
5550 // For reading/writing settings file.
5551 private final ArrayList<Signature> mPastSignatures =
5552 new ArrayList<Signature>();
5553
5554 // Mapping from permission names to info about them.
5555 final HashMap<String, BasePermission> mPermissions =
5556 new HashMap<String, BasePermission>();
5557
5558 // Mapping from permission tree names to info about them.
5559 final HashMap<String, BasePermission> mPermissionTrees =
5560 new HashMap<String, BasePermission>();
5561
5562 private final ArrayList<String> mPendingPreferredPackages
5563 = new ArrayList<String>();
5564
5565 private final StringBuilder mReadMessages = new StringBuilder();
5566
5567 private static final class PendingPackage extends PackageSettingBase {
5568 final int sharedId;
5569
5570 PendingPackage(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005571 int sharedId, int pVersionCode, int pkgFlags) {
5572 super(name, codePath, resourcePath, pVersionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005573 this.sharedId = sharedId;
5574 }
5575 }
5576 private final ArrayList<PendingPackage> mPendingPackages
5577 = new ArrayList<PendingPackage>();
5578
5579 Settings() {
5580 File dataDir = Environment.getDataDirectory();
5581 File systemDir = new File(dataDir, "system");
5582 systemDir.mkdirs();
5583 FileUtils.setPermissions(systemDir.toString(),
5584 FileUtils.S_IRWXU|FileUtils.S_IRWXG
5585 |FileUtils.S_IROTH|FileUtils.S_IXOTH,
5586 -1, -1);
5587 mSettingsFilename = new File(systemDir, "packages.xml");
5588 mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
5589 }
5590
5591 PackageSetting getPackageLP(PackageParser.Package pkg,
5592 SharedUserSetting sharedUser, File codePath, File resourcePath,
5593 int pkgFlags, boolean create, boolean add) {
5594 final String name = pkg.packageName;
5595 PackageSetting p = getPackageLP(name, sharedUser, codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005596 resourcePath, pkg.mVersionCode, pkgFlags, create, add);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005597
5598 if (p != null) {
5599 p.pkg = pkg;
5600 }
5601 return p;
5602 }
5603
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005604 PackageSetting peekPackageLP(String name) {
5605 return mPackages.get(name);
5606 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005607 PackageSetting p = mPackages.get(name);
5608 if (p != null && p.codePath.getPath().equals(codePath)) {
5609 return p;
5610 }
5611 return null;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005612 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005613 }
5614
5615 void setInstallStatus(String pkgName, int status) {
5616 PackageSetting p = mPackages.get(pkgName);
5617 if(p != null) {
5618 if(p.getInstallStatus() != status) {
5619 p.setInstallStatus(status);
5620 }
5621 }
5622 }
5623
Jacek Surazskic64322c2009-04-28 15:26:38 +02005624 void setInstallerPackageName(String pkgName,
5625 String installerPkgName) {
5626 PackageSetting p = mPackages.get(pkgName);
5627 if(p != null) {
5628 p.setInstallerPackageName(installerPkgName);
5629 }
5630 }
5631
5632 String getInstallerPackageName(String pkgName) {
5633 PackageSetting p = mPackages.get(pkgName);
5634 return (p == null) ? null : p.getInstallerPackageName();
5635 }
5636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005637 int getInstallStatus(String pkgName) {
5638 PackageSetting p = mPackages.get(pkgName);
5639 if(p != null) {
5640 return p.getInstallStatus();
5641 }
5642 return -1;
5643 }
5644
5645 SharedUserSetting getSharedUserLP(String name,
5646 int pkgFlags, boolean create) {
5647 SharedUserSetting s = mSharedUsers.get(name);
5648 if (s == null) {
5649 if (!create) {
5650 return null;
5651 }
5652 s = new SharedUserSetting(name, pkgFlags);
5653 if (MULTIPLE_APPLICATION_UIDS) {
5654 s.userId = newUserIdLP(s);
5655 } else {
5656 s.userId = FIRST_APPLICATION_UID;
5657 }
5658 Log.i(TAG, "New shared user " + name + ": id=" + s.userId);
5659 // < 0 means we couldn't assign a userid; fall out and return
5660 // s, which is currently null
5661 if (s.userId >= 0) {
5662 mSharedUsers.put(name, s);
5663 }
5664 }
5665
5666 return s;
5667 }
5668
5669 int disableSystemPackageLP(String name) {
5670 PackageSetting p = mPackages.get(name);
5671 if(p == null) {
5672 Log.w(TAG, "Package:"+name+" is not an installed package");
5673 return -1;
5674 }
5675 PackageSetting dp = mDisabledSysPackages.get(name);
5676 // always make sure the system package code and resource paths dont change
5677 if(dp == null) {
5678 if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
5679 p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
5680 }
5681 mDisabledSysPackages.put(name, p);
5682 }
5683 return removePackageLP(name);
5684 }
5685
5686 PackageSetting enableSystemPackageLP(String name) {
5687 PackageSetting p = mDisabledSysPackages.get(name);
5688 if(p == null) {
5689 Log.w(TAG, "Package:"+name+" is not disabled");
5690 return null;
5691 }
5692 // Reset flag in ApplicationInfo object
5693 if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
5694 p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
5695 }
5696 PackageSetting ret = addPackageLP(name, p.codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005697 p.resourcePath, p.userId, p.versionCode, p.pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005698 mDisabledSysPackages.remove(name);
5699 return ret;
5700 }
5701
5702 PackageSetting addPackageLP(String name, File codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005703 File resourcePath, int uid, int vc, int pkgFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005704 PackageSetting p = mPackages.get(name);
5705 if (p != null) {
5706 if (p.userId == uid) {
5707 return p;
5708 }
5709 reportSettingsProblem(Log.ERROR,
5710 "Adding duplicate package, keeping first: " + name);
5711 return null;
5712 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005713 p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005714 p.userId = uid;
5715 if (addUserIdLP(uid, p, name)) {
5716 mPackages.put(name, p);
5717 return p;
5718 }
5719 return null;
5720 }
5721
5722 SharedUserSetting addSharedUserLP(String name, int uid, int pkgFlags) {
5723 SharedUserSetting s = mSharedUsers.get(name);
5724 if (s != null) {
5725 if (s.userId == uid) {
5726 return s;
5727 }
5728 reportSettingsProblem(Log.ERROR,
5729 "Adding duplicate shared user, keeping first: " + name);
5730 return null;
5731 }
5732 s = new SharedUserSetting(name, pkgFlags);
5733 s.userId = uid;
5734 if (addUserIdLP(uid, s, name)) {
5735 mSharedUsers.put(name, s);
5736 return s;
5737 }
5738 return null;
5739 }
5740
5741 private PackageSetting getPackageLP(String name,
5742 SharedUserSetting sharedUser, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005743 int vc, int pkgFlags, boolean create, boolean add) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005744 PackageSetting p = mPackages.get(name);
5745 if (p != null) {
5746 if (!p.codePath.equals(codePath)) {
5747 // Check to see if its a disabled system app
5748 PackageSetting ps = mDisabledSysPackages.get(name);
5749 if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
5750 // Could be a replaced system package
5751 // Note that if the user replaced a system app, the user has to physically
5752 // delete the new one in order to revert to the system app. So even
5753 // if the user updated the system app via an update, the user still
5754 // has to delete the one installed in the data partition in order to pick up the
5755 // new system package.
5756 return p;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07005757 } else if ((p.pkg != null) && (p.pkg.applicationInfo != null) &&
5758 ((p.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
5759 // Check for non-system apps
5760 reportSettingsProblem(Log.WARN,
5761 "Package " + name + " codePath changed from " + p.codePath
5762 + " to " + codePath + "; Retaining data and using new code");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005763 } else {
5764 reportSettingsProblem(Log.WARN,
5765 "Package " + name + " codePath changed from " + p.codePath
5766 + " to " + codePath + "; replacing with new");
5767 p = null;
5768 }
5769 } else if (p.sharedUser != sharedUser) {
5770 reportSettingsProblem(Log.WARN,
5771 "Package " + name + " shared user changed from "
5772 + (p.sharedUser != null ? p.sharedUser.name : "<nothing>")
5773 + " to "
5774 + (sharedUser != null ? sharedUser.name : "<nothing>")
5775 + "; replacing with new");
5776 p = null;
5777 }
5778 }
5779 if (p == null) {
5780 // Create a new PackageSettings entry. this can end up here because
5781 // of code path mismatch or user id mismatch of an updated system partition
5782 if (!create) {
5783 return null;
5784 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005785 p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005786 p.setTimeStamp(codePath.lastModified());
Dianne Hackborn5d6d7732009-05-13 18:09:56 -07005787 p.sharedUser = sharedUser;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005788 if (sharedUser != null) {
5789 p.userId = sharedUser.userId;
5790 } else if (MULTIPLE_APPLICATION_UIDS) {
5791 p.userId = newUserIdLP(p);
5792 } else {
5793 p.userId = FIRST_APPLICATION_UID;
5794 }
5795 if (p.userId < 0) {
5796 reportSettingsProblem(Log.WARN,
5797 "Package " + name + " could not be assigned a valid uid");
5798 return null;
5799 }
5800 if (add) {
5801 // Finish adding new package by adding it and updating shared
5802 // user preferences
5803 insertPackageSettingLP(p, name, sharedUser);
5804 }
5805 }
5806 return p;
5807 }
5808
5809 // Utility method that adds a PackageSetting to mPackages and
5810 // completes updating the shared user attributes
5811 private void insertPackageSettingLP(PackageSetting p, String name,
5812 SharedUserSetting sharedUser) {
5813 mPackages.put(name, p);
5814 if (sharedUser != null) {
5815 if (p.sharedUser != null && p.sharedUser != sharedUser) {
5816 reportSettingsProblem(Log.ERROR,
5817 "Package " + p.name + " was user "
5818 + p.sharedUser + " but is now " + sharedUser
5819 + "; I am not changing its files so it will probably fail!");
5820 p.sharedUser.packages.remove(p);
5821 } else if (p.userId != sharedUser.userId) {
5822 reportSettingsProblem(Log.ERROR,
5823 "Package " + p.name + " was user id " + p.userId
5824 + " but is now user " + sharedUser
5825 + " with id " + sharedUser.userId
5826 + "; I am not changing its files so it will probably fail!");
5827 }
5828
5829 sharedUser.packages.add(p);
5830 p.sharedUser = sharedUser;
5831 p.userId = sharedUser.userId;
5832 }
5833 }
5834
5835 private void updateSharedUserPerms (PackageSetting deletedPs) {
5836 if ( (deletedPs == null) || (deletedPs.pkg == null)) {
5837 Log.i(TAG, "Trying to update info for null package. Just ignoring");
5838 return;
5839 }
5840 // No sharedUserId
5841 if (deletedPs.sharedUser == null) {
5842 return;
5843 }
5844 SharedUserSetting sus = deletedPs.sharedUser;
5845 // Update permissions
5846 for (String eachPerm: deletedPs.pkg.requestedPermissions) {
5847 boolean used = false;
5848 if (!sus.grantedPermissions.contains (eachPerm)) {
5849 continue;
5850 }
5851 for (PackageSetting pkg:sus.packages) {
5852 if (pkg.grantedPermissions.contains (eachPerm)) {
5853 used = true;
5854 break;
5855 }
5856 }
5857 if (!used) {
5858 // can safely delete this permission from list
5859 sus.grantedPermissions.remove(eachPerm);
5860 sus.loadedPermissions.remove(eachPerm);
5861 }
5862 }
5863 // Update gids
5864 int newGids[] = null;
5865 for (PackageSetting pkg:sus.packages) {
5866 newGids = appendInts(newGids, pkg.gids);
5867 }
5868 sus.gids = newGids;
5869 }
5870
5871 private int removePackageLP(String name) {
5872 PackageSetting p = mPackages.get(name);
5873 if (p != null) {
5874 mPackages.remove(name);
5875 if (p.sharedUser != null) {
5876 p.sharedUser.packages.remove(p);
5877 if (p.sharedUser.packages.size() == 0) {
5878 mSharedUsers.remove(p.sharedUser.name);
5879 removeUserIdLP(p.sharedUser.userId);
5880 return p.sharedUser.userId;
5881 }
5882 } else {
5883 removeUserIdLP(p.userId);
5884 return p.userId;
5885 }
5886 }
5887 return -1;
5888 }
5889
5890 private boolean addUserIdLP(int uid, Object obj, Object name) {
5891 if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) {
5892 return false;
5893 }
5894
5895 if (uid >= FIRST_APPLICATION_UID) {
5896 int N = mUserIds.size();
5897 final int index = uid - FIRST_APPLICATION_UID;
5898 while (index >= N) {
5899 mUserIds.add(null);
5900 N++;
5901 }
5902 if (mUserIds.get(index) != null) {
5903 reportSettingsProblem(Log.ERROR,
5904 "Adding duplicate shared id: " + uid
5905 + " name=" + name);
5906 return false;
5907 }
5908 mUserIds.set(index, obj);
5909 } else {
5910 if (mOtherUserIds.get(uid) != null) {
5911 reportSettingsProblem(Log.ERROR,
5912 "Adding duplicate shared id: " + uid
5913 + " name=" + name);
5914 return false;
5915 }
5916 mOtherUserIds.put(uid, obj);
5917 }
5918 return true;
5919 }
5920
5921 public Object getUserIdLP(int uid) {
5922 if (uid >= FIRST_APPLICATION_UID) {
5923 int N = mUserIds.size();
5924 final int index = uid - FIRST_APPLICATION_UID;
5925 return index < N ? mUserIds.get(index) : null;
5926 } else {
5927 return mOtherUserIds.get(uid);
5928 }
5929 }
5930
5931 private void removeUserIdLP(int uid) {
5932 if (uid >= FIRST_APPLICATION_UID) {
5933 int N = mUserIds.size();
5934 final int index = uid - FIRST_APPLICATION_UID;
5935 if (index < N) mUserIds.set(index, null);
5936 } else {
5937 mOtherUserIds.remove(uid);
5938 }
5939 }
5940
5941 void writeLP() {
5942 //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
5943
5944 // Keep the old settings around until we know the new ones have
5945 // been successfully written.
5946 if (mSettingsFilename.exists()) {
5947 if (mBackupSettingsFilename.exists()) {
5948 mBackupSettingsFilename.delete();
5949 }
5950 mSettingsFilename.renameTo(mBackupSettingsFilename);
5951 }
5952
5953 mPastSignatures.clear();
5954
5955 try {
5956 FileOutputStream str = new FileOutputStream(mSettingsFilename);
5957
5958 //XmlSerializer serializer = XmlUtils.serializerInstance();
5959 XmlSerializer serializer = new FastXmlSerializer();
5960 serializer.setOutput(str, "utf-8");
5961 serializer.startDocument(null, true);
5962 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
5963
5964 serializer.startTag(null, "packages");
5965
5966 serializer.startTag(null, "permission-trees");
5967 for (BasePermission bp : mPermissionTrees.values()) {
5968 writePermission(serializer, bp);
5969 }
5970 serializer.endTag(null, "permission-trees");
5971
5972 serializer.startTag(null, "permissions");
5973 for (BasePermission bp : mPermissions.values()) {
5974 writePermission(serializer, bp);
5975 }
5976 serializer.endTag(null, "permissions");
5977
5978 for (PackageSetting pkg : mPackages.values()) {
5979 writePackage(serializer, pkg);
5980 }
5981
5982 for (PackageSetting pkg : mDisabledSysPackages.values()) {
5983 writeDisabledSysPackage(serializer, pkg);
5984 }
5985
5986 serializer.startTag(null, "preferred-packages");
5987 int N = mPreferredPackages.size();
5988 for (int i=0; i<N; i++) {
5989 PackageSetting pkg = mPreferredPackages.get(i);
5990 serializer.startTag(null, "item");
5991 serializer.attribute(null, "name", pkg.name);
5992 serializer.endTag(null, "item");
5993 }
5994 serializer.endTag(null, "preferred-packages");
5995
5996 serializer.startTag(null, "preferred-activities");
5997 for (PreferredActivity pa : mPreferredActivities.filterSet()) {
5998 serializer.startTag(null, "item");
5999 pa.writeToXml(serializer);
6000 serializer.endTag(null, "item");
6001 }
6002 serializer.endTag(null, "preferred-activities");
6003
6004 for (SharedUserSetting usr : mSharedUsers.values()) {
6005 serializer.startTag(null, "shared-user");
6006 serializer.attribute(null, "name", usr.name);
6007 serializer.attribute(null, "userId",
6008 Integer.toString(usr.userId));
6009 usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
6010 serializer.startTag(null, "perms");
6011 for (String name : usr.grantedPermissions) {
6012 serializer.startTag(null, "item");
6013 serializer.attribute(null, "name", name);
6014 serializer.endTag(null, "item");
6015 }
6016 serializer.endTag(null, "perms");
6017 serializer.endTag(null, "shared-user");
6018 }
6019
6020 serializer.endTag(null, "packages");
6021
6022 serializer.endDocument();
6023
6024 str.flush();
6025 str.close();
6026
6027 // New settings successfully written, old ones are no longer
6028 // needed.
6029 mBackupSettingsFilename.delete();
6030 FileUtils.setPermissions(mSettingsFilename.toString(),
6031 FileUtils.S_IRUSR|FileUtils.S_IWUSR
6032 |FileUtils.S_IRGRP|FileUtils.S_IWGRP
6033 |FileUtils.S_IROTH,
6034 -1, -1);
6035
6036 } catch(XmlPullParserException e) {
6037 Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
6038
6039 } catch(java.io.IOException e) {
6040 Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
6041
6042 }
6043
6044 //Debug.stopMethodTracing();
6045 }
6046
6047 void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
6048 throws java.io.IOException {
6049 serializer.startTag(null, "updated-package");
6050 serializer.attribute(null, "name", pkg.name);
6051 serializer.attribute(null, "codePath", pkg.codePathString);
6052 serializer.attribute(null, "ts", pkg.getTimeStampStr());
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006053 serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006054 if (!pkg.resourcePathString.equals(pkg.codePathString)) {
6055 serializer.attribute(null, "resourcePath", pkg.resourcePathString);
6056 }
6057 if (pkg.sharedUser == null) {
6058 serializer.attribute(null, "userId",
6059 Integer.toString(pkg.userId));
6060 } else {
6061 serializer.attribute(null, "sharedUserId",
6062 Integer.toString(pkg.userId));
6063 }
6064 serializer.startTag(null, "perms");
6065 if (pkg.sharedUser == null) {
6066 // If this is a shared user, the permissions will
6067 // be written there. We still need to write an
6068 // empty permissions list so permissionsFixed will
6069 // be set.
6070 for (final String name : pkg.grantedPermissions) {
6071 BasePermission bp = mPermissions.get(name);
6072 if ((bp != null) && (bp.perm != null) && (bp.perm.info != null)) {
6073 // We only need to write signature or system permissions but this wont
6074 // match the semantics of grantedPermissions. So write all permissions.
6075 serializer.startTag(null, "item");
6076 serializer.attribute(null, "name", name);
6077 serializer.endTag(null, "item");
6078 }
6079 }
6080 }
6081 serializer.endTag(null, "perms");
6082 serializer.endTag(null, "updated-package");
6083 }
6084
6085 void writePackage(XmlSerializer serializer, final PackageSetting pkg)
6086 throws java.io.IOException {
6087 serializer.startTag(null, "package");
6088 serializer.attribute(null, "name", pkg.name);
6089 serializer.attribute(null, "codePath", pkg.codePathString);
6090 if (!pkg.resourcePathString.equals(pkg.codePathString)) {
6091 serializer.attribute(null, "resourcePath", pkg.resourcePathString);
6092 }
6093 serializer.attribute(null, "system",
6094 (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
6095 ? "true" : "false");
6096 serializer.attribute(null, "ts", pkg.getTimeStampStr());
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006097 serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006098 if (pkg.sharedUser == null) {
6099 serializer.attribute(null, "userId",
6100 Integer.toString(pkg.userId));
6101 } else {
6102 serializer.attribute(null, "sharedUserId",
6103 Integer.toString(pkg.userId));
6104 }
6105 if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
6106 serializer.attribute(null, "enabled",
6107 pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
6108 ? "true" : "false");
6109 }
6110 if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
6111 serializer.attribute(null, "installStatus", "false");
6112 }
Jacek Surazskic64322c2009-04-28 15:26:38 +02006113 if (pkg.installerPackageName != null) {
6114 serializer.attribute(null, "installer", pkg.installerPackageName);
6115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006116 pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
6117 if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
6118 serializer.startTag(null, "perms");
6119 if (pkg.sharedUser == null) {
6120 // If this is a shared user, the permissions will
6121 // be written there. We still need to write an
6122 // empty permissions list so permissionsFixed will
6123 // be set.
6124 for (final String name : pkg.grantedPermissions) {
6125 serializer.startTag(null, "item");
6126 serializer.attribute(null, "name", name);
6127 serializer.endTag(null, "item");
6128 }
6129 }
6130 serializer.endTag(null, "perms");
6131 }
6132 if (pkg.disabledComponents.size() > 0) {
6133 serializer.startTag(null, "disabled-components");
6134 for (final String name : pkg.disabledComponents) {
6135 serializer.startTag(null, "item");
6136 serializer.attribute(null, "name", name);
6137 serializer.endTag(null, "item");
6138 }
6139 serializer.endTag(null, "disabled-components");
6140 }
6141 if (pkg.enabledComponents.size() > 0) {
6142 serializer.startTag(null, "enabled-components");
6143 for (final String name : pkg.enabledComponents) {
6144 serializer.startTag(null, "item");
6145 serializer.attribute(null, "name", name);
6146 serializer.endTag(null, "item");
6147 }
6148 serializer.endTag(null, "enabled-components");
6149 }
Jacek Surazskic64322c2009-04-28 15:26:38 +02006150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006151 serializer.endTag(null, "package");
6152 }
6153
6154 void writePermission(XmlSerializer serializer, BasePermission bp)
6155 throws XmlPullParserException, java.io.IOException {
6156 if (bp.type != BasePermission.TYPE_BUILTIN
6157 && bp.sourcePackage != null) {
6158 serializer.startTag(null, "item");
6159 serializer.attribute(null, "name", bp.name);
6160 serializer.attribute(null, "package", bp.sourcePackage);
6161 if (DEBUG_SETTINGS) Log.v(TAG,
6162 "Writing perm: name=" + bp.name + " type=" + bp.type);
6163 if (bp.type == BasePermission.TYPE_DYNAMIC) {
6164 PermissionInfo pi = bp.perm != null ? bp.perm.info
6165 : bp.pendingInfo;
6166 if (pi != null) {
6167 serializer.attribute(null, "type", "dynamic");
6168 if (pi.icon != 0) {
6169 serializer.attribute(null, "icon",
6170 Integer.toString(pi.icon));
6171 }
6172 if (pi.nonLocalizedLabel != null) {
6173 serializer.attribute(null, "label",
6174 pi.nonLocalizedLabel.toString());
6175 }
6176 if (pi.protectionLevel !=
6177 PermissionInfo.PROTECTION_NORMAL) {
6178 serializer.attribute(null, "protection",
6179 Integer.toString(pi.protectionLevel));
6180 }
6181 }
6182 }
6183 serializer.endTag(null, "item");
6184 }
6185 }
6186
6187 String getReadMessagesLP() {
6188 return mReadMessages.toString();
6189 }
6190
6191 ArrayList<String> getListOfIncompleteInstallPackages() {
6192 HashSet<String> kList = new HashSet<String>(mPackages.keySet());
6193 Iterator<String> its = kList.iterator();
6194 ArrayList<String> ret = new ArrayList<String>();
6195 while(its.hasNext()) {
6196 String key = its.next();
6197 PackageSetting ps = mPackages.get(key);
6198 if(ps.getInstallStatus() == PKG_INSTALL_INCOMPLETE) {
6199 ret.add(key);
6200 }
6201 }
6202 return ret;
6203 }
6204
6205 boolean readLP() {
6206 FileInputStream str = null;
6207 if (mBackupSettingsFilename.exists()) {
6208 try {
6209 str = new FileInputStream(mBackupSettingsFilename);
6210 mReadMessages.append("Reading from backup settings file\n");
6211 Log.i(TAG, "Reading from backup settings file!");
6212 } catch (java.io.IOException e) {
6213 // We'll try for the normal settings file.
6214 }
6215 }
6216
6217 mPastSignatures.clear();
6218
6219 try {
6220 if (str == null) {
6221 if (!mSettingsFilename.exists()) {
6222 mReadMessages.append("No settings file found\n");
6223 Log.i(TAG, "No current settings file!");
6224 return false;
6225 }
6226 str = new FileInputStream(mSettingsFilename);
6227 }
6228 XmlPullParser parser = Xml.newPullParser();
6229 parser.setInput(str, null);
6230
6231 int type;
6232 while ((type=parser.next()) != XmlPullParser.START_TAG
6233 && type != XmlPullParser.END_DOCUMENT) {
6234 ;
6235 }
6236
6237 if (type != XmlPullParser.START_TAG) {
6238 mReadMessages.append("No start tag found in settings file\n");
6239 Log.e(TAG, "No start tag found in package manager settings");
6240 return false;
6241 }
6242
6243 int outerDepth = parser.getDepth();
6244 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6245 && (type != XmlPullParser.END_TAG
6246 || parser.getDepth() > outerDepth)) {
6247 if (type == XmlPullParser.END_TAG
6248 || type == XmlPullParser.TEXT) {
6249 continue;
6250 }
6251
6252 String tagName = parser.getName();
6253 if (tagName.equals("package")) {
6254 readPackageLP(parser);
6255 } else if (tagName.equals("permissions")) {
6256 readPermissionsLP(mPermissions, parser);
6257 } else if (tagName.equals("permission-trees")) {
6258 readPermissionsLP(mPermissionTrees, parser);
6259 } else if (tagName.equals("shared-user")) {
6260 readSharedUserLP(parser);
6261 } else if (tagName.equals("preferred-packages")) {
6262 readPreferredPackagesLP(parser);
6263 } else if (tagName.equals("preferred-activities")) {
6264 readPreferredActivitiesLP(parser);
6265 } else if(tagName.equals("updated-package")) {
6266 readDisabledSysPackageLP(parser);
6267 } else {
6268 Log.w(TAG, "Unknown element under <packages>: "
6269 + parser.getName());
6270 XmlUtils.skipCurrentTag(parser);
6271 }
6272 }
6273
6274 str.close();
6275
6276 } catch(XmlPullParserException e) {
6277 mReadMessages.append("Error reading: " + e.toString());
6278 Log.e(TAG, "Error reading package manager settings", e);
6279
6280 } catch(java.io.IOException e) {
6281 mReadMessages.append("Error reading: " + e.toString());
6282 Log.e(TAG, "Error reading package manager settings", e);
6283
6284 }
6285
6286 int N = mPendingPackages.size();
6287 for (int i=0; i<N; i++) {
6288 final PendingPackage pp = mPendingPackages.get(i);
6289 Object idObj = getUserIdLP(pp.sharedId);
6290 if (idObj != null && idObj instanceof SharedUserSetting) {
6291 PackageSetting p = getPackageLP(pp.name,
6292 (SharedUserSetting)idObj, pp.codePath, pp.resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006293 pp.versionCode, pp.pkgFlags, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006294 if (p == null) {
6295 Log.w(TAG, "Unable to create application package for "
6296 + pp.name);
6297 continue;
6298 }
6299 p.copyFrom(pp);
6300 } else if (idObj != null) {
6301 String msg = "Bad package setting: package " + pp.name
6302 + " has shared uid " + pp.sharedId
6303 + " that is not a shared uid\n";
6304 mReadMessages.append(msg);
6305 Log.e(TAG, msg);
6306 } else {
6307 String msg = "Bad package setting: package " + pp.name
6308 + " has shared uid " + pp.sharedId
6309 + " that is not defined\n";
6310 mReadMessages.append(msg);
6311 Log.e(TAG, msg);
6312 }
6313 }
6314 mPendingPackages.clear();
6315
6316 N = mPendingPreferredPackages.size();
6317 mPreferredPackages.clear();
6318 for (int i=0; i<N; i++) {
6319 final String name = mPendingPreferredPackages.get(i);
6320 final PackageSetting p = mPackages.get(name);
6321 if (p != null) {
6322 mPreferredPackages.add(p);
6323 } else {
6324 Log.w(TAG, "Unknown preferred package: " + name);
6325 }
6326 }
6327 mPendingPreferredPackages.clear();
6328
6329 mReadMessages.append("Read completed successfully: "
6330 + mPackages.size() + " packages, "
6331 + mSharedUsers.size() + " shared uids\n");
6332
6333 return true;
6334 }
6335
6336 private int readInt(XmlPullParser parser, String ns, String name,
6337 int defValue) {
6338 String v = parser.getAttributeValue(ns, name);
6339 try {
6340 if (v == null) {
6341 return defValue;
6342 }
6343 return Integer.parseInt(v);
6344 } catch (NumberFormatException e) {
6345 reportSettingsProblem(Log.WARN,
6346 "Error in package manager settings: attribute " +
6347 name + " has bad integer value " + v + " at "
6348 + parser.getPositionDescription());
6349 }
6350 return defValue;
6351 }
6352
6353 private void readPermissionsLP(HashMap<String, BasePermission> out,
6354 XmlPullParser parser)
6355 throws IOException, XmlPullParserException {
6356 int outerDepth = parser.getDepth();
6357 int type;
6358 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6359 && (type != XmlPullParser.END_TAG
6360 || parser.getDepth() > outerDepth)) {
6361 if (type == XmlPullParser.END_TAG
6362 || type == XmlPullParser.TEXT) {
6363 continue;
6364 }
6365
6366 String tagName = parser.getName();
6367 if (tagName.equals("item")) {
6368 String name = parser.getAttributeValue(null, "name");
6369 String sourcePackage = parser.getAttributeValue(null, "package");
6370 String ptype = parser.getAttributeValue(null, "type");
6371 if (name != null && sourcePackage != null) {
6372 boolean dynamic = "dynamic".equals(ptype);
6373 BasePermission bp = new BasePermission(name, sourcePackage,
6374 dynamic
6375 ? BasePermission.TYPE_DYNAMIC
6376 : BasePermission.TYPE_NORMAL);
6377 if (dynamic) {
6378 PermissionInfo pi = new PermissionInfo();
6379 pi.packageName = sourcePackage.intern();
6380 pi.name = name.intern();
6381 pi.icon = readInt(parser, null, "icon", 0);
6382 pi.nonLocalizedLabel = parser.getAttributeValue(
6383 null, "label");
6384 pi.protectionLevel = readInt(parser, null, "protection",
6385 PermissionInfo.PROTECTION_NORMAL);
6386 bp.pendingInfo = pi;
6387 }
6388 out.put(bp.name, bp);
6389 } else {
6390 reportSettingsProblem(Log.WARN,
6391 "Error in package manager settings: permissions has"
6392 + " no name at " + parser.getPositionDescription());
6393 }
6394 } else {
6395 reportSettingsProblem(Log.WARN,
6396 "Unknown element reading permissions: "
6397 + parser.getName() + " at "
6398 + parser.getPositionDescription());
6399 }
6400 XmlUtils.skipCurrentTag(parser);
6401 }
6402 }
6403
6404 private void readDisabledSysPackageLP(XmlPullParser parser)
6405 throws XmlPullParserException, IOException {
6406 String name = parser.getAttributeValue(null, "name");
6407 String codePathStr = parser.getAttributeValue(null, "codePath");
6408 String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
6409 if(resourcePathStr == null) {
6410 resourcePathStr = codePathStr;
6411 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006412 String version = parser.getAttributeValue(null, "version");
6413 int versionCode = 0;
6414 if (version != null) {
6415 try {
6416 versionCode = Integer.parseInt(version);
6417 } catch (NumberFormatException e) {
6418 }
6419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006420
6421 int pkgFlags = 0;
6422 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6423 PackageSetting ps = new PackageSetting(name,
6424 new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006425 new File(resourcePathStr), versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006426 String timeStampStr = parser.getAttributeValue(null, "ts");
6427 if (timeStampStr != null) {
6428 try {
6429 long timeStamp = Long.parseLong(timeStampStr);
6430 ps.setTimeStamp(timeStamp, timeStampStr);
6431 } catch (NumberFormatException e) {
6432 }
6433 }
6434 String idStr = parser.getAttributeValue(null, "userId");
6435 ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
6436 if(ps.userId <= 0) {
6437 String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
6438 ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
6439 }
6440 int outerDepth = parser.getDepth();
6441 int type;
6442 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6443 && (type != XmlPullParser.END_TAG
6444 || parser.getDepth() > outerDepth)) {
6445 if (type == XmlPullParser.END_TAG
6446 || type == XmlPullParser.TEXT) {
6447 continue;
6448 }
6449
6450 String tagName = parser.getName();
6451 if (tagName.equals("perms")) {
6452 readGrantedPermissionsLP(parser,
6453 ps.grantedPermissions);
6454 } else {
6455 reportSettingsProblem(Log.WARN,
6456 "Unknown element under <updated-package>: "
6457 + parser.getName());
6458 XmlUtils.skipCurrentTag(parser);
6459 }
6460 }
6461 mDisabledSysPackages.put(name, ps);
6462 }
6463
6464 private void readPackageLP(XmlPullParser parser)
6465 throws XmlPullParserException, IOException {
6466 String name = null;
6467 String idStr = null;
6468 String sharedIdStr = null;
6469 String codePathStr = null;
6470 String resourcePathStr = null;
6471 String systemStr = null;
Jacek Surazskic64322c2009-04-28 15:26:38 +02006472 String installerPackageName = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006473 int pkgFlags = 0;
6474 String timeStampStr;
6475 long timeStamp = 0;
6476 PackageSettingBase packageSetting = null;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006477 String version = null;
6478 int versionCode = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006479 try {
6480 name = parser.getAttributeValue(null, "name");
6481 idStr = parser.getAttributeValue(null, "userId");
6482 sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
6483 codePathStr = parser.getAttributeValue(null, "codePath");
6484 resourcePathStr = parser.getAttributeValue(null, "resourcePath");
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006485 version = parser.getAttributeValue(null, "version");
6486 if (version != null) {
6487 try {
6488 versionCode = Integer.parseInt(version);
6489 } catch (NumberFormatException e) {
6490 }
6491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006492 systemStr = parser.getAttributeValue(null, "system");
Jacek Surazskic64322c2009-04-28 15:26:38 +02006493 installerPackageName = parser.getAttributeValue(null, "installer");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006494 if (systemStr != null) {
6495 if ("true".equals(systemStr)) {
6496 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6497 }
6498 } else {
6499 // Old settings that don't specify system... just treat
6500 // them as system, good enough.
6501 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6502 }
6503 timeStampStr = parser.getAttributeValue(null, "ts");
6504 if (timeStampStr != null) {
6505 try {
6506 timeStamp = Long.parseLong(timeStampStr);
6507 } catch (NumberFormatException e) {
6508 }
6509 }
6510 if (DEBUG_SETTINGS) Log.v(TAG, "Reading package: " + name
6511 + " userId=" + idStr + " sharedUserId=" + sharedIdStr);
6512 int userId = idStr != null ? Integer.parseInt(idStr) : 0;
6513 if (resourcePathStr == null) {
6514 resourcePathStr = codePathStr;
6515 }
6516 if (name == null) {
6517 reportSettingsProblem(Log.WARN,
6518 "Error in package manager settings: <package> has no name at "
6519 + parser.getPositionDescription());
6520 } else if (codePathStr == null) {
6521 reportSettingsProblem(Log.WARN,
6522 "Error in package manager settings: <package> has no codePath at "
6523 + parser.getPositionDescription());
6524 } else if (userId > 0) {
6525 packageSetting = addPackageLP(name.intern(), new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006526 new File(resourcePathStr), userId, versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006527 if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
6528 + ": userId=" + userId + " pkg=" + packageSetting);
6529 if (packageSetting == null) {
6530 reportSettingsProblem(Log.ERROR,
6531 "Failure adding uid " + userId
6532 + " while parsing settings at "
6533 + parser.getPositionDescription());
6534 } else {
6535 packageSetting.setTimeStamp(timeStamp, timeStampStr);
6536 }
6537 } else if (sharedIdStr != null) {
6538 userId = sharedIdStr != null
6539 ? Integer.parseInt(sharedIdStr) : 0;
6540 if (userId > 0) {
6541 packageSetting = new PendingPackage(name.intern(), new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006542 new File(resourcePathStr), userId, versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006543 packageSetting.setTimeStamp(timeStamp, timeStampStr);
6544 mPendingPackages.add((PendingPackage) packageSetting);
6545 if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
6546 + ": sharedUserId=" + userId + " pkg="
6547 + packageSetting);
6548 } else {
6549 reportSettingsProblem(Log.WARN,
6550 "Error in package manager settings: package "
6551 + name + " has bad sharedId " + sharedIdStr
6552 + " at " + parser.getPositionDescription());
6553 }
6554 } else {
6555 reportSettingsProblem(Log.WARN,
6556 "Error in package manager settings: package "
6557 + name + " has bad userId " + idStr + " at "
6558 + parser.getPositionDescription());
6559 }
6560 } catch (NumberFormatException e) {
6561 reportSettingsProblem(Log.WARN,
6562 "Error in package manager settings: package "
6563 + name + " has bad userId " + idStr + " at "
6564 + parser.getPositionDescription());
6565 }
6566 if (packageSetting != null) {
Jacek Surazskic64322c2009-04-28 15:26:38 +02006567 packageSetting.installerPackageName = installerPackageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006568 final String enabledStr = parser.getAttributeValue(null, "enabled");
6569 if (enabledStr != null) {
6570 if (enabledStr.equalsIgnoreCase("true")) {
6571 packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
6572 } else if (enabledStr.equalsIgnoreCase("false")) {
6573 packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
6574 } else if (enabledStr.equalsIgnoreCase("default")) {
6575 packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
6576 } else {
6577 reportSettingsProblem(Log.WARN,
6578 "Error in package manager settings: package "
6579 + name + " has bad enabled value: " + idStr
6580 + " at " + parser.getPositionDescription());
6581 }
6582 } else {
6583 packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
6584 }
6585 final String installStatusStr = parser.getAttributeValue(null, "installStatus");
6586 if (installStatusStr != null) {
6587 if (installStatusStr.equalsIgnoreCase("false")) {
6588 packageSetting.installStatus = PKG_INSTALL_INCOMPLETE;
6589 } else {
6590 packageSetting.installStatus = PKG_INSTALL_COMPLETE;
6591 }
6592 }
6593
6594 int outerDepth = parser.getDepth();
6595 int type;
6596 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6597 && (type != XmlPullParser.END_TAG
6598 || parser.getDepth() > outerDepth)) {
6599 if (type == XmlPullParser.END_TAG
6600 || type == XmlPullParser.TEXT) {
6601 continue;
6602 }
6603
6604 String tagName = parser.getName();
6605 if (tagName.equals("disabled-components")) {
6606 readDisabledComponentsLP(packageSetting, parser);
6607 } else if (tagName.equals("enabled-components")) {
6608 readEnabledComponentsLP(packageSetting, parser);
6609 } else if (tagName.equals("sigs")) {
6610 packageSetting.signatures.readXml(parser, mPastSignatures);
6611 } else if (tagName.equals("perms")) {
6612 readGrantedPermissionsLP(parser,
6613 packageSetting.loadedPermissions);
6614 packageSetting.permissionsFixed = true;
6615 } else {
6616 reportSettingsProblem(Log.WARN,
6617 "Unknown element under <package>: "
6618 + parser.getName());
6619 XmlUtils.skipCurrentTag(parser);
6620 }
6621 }
6622 } else {
6623 XmlUtils.skipCurrentTag(parser);
6624 }
6625 }
6626
6627 private void readDisabledComponentsLP(PackageSettingBase packageSetting,
6628 XmlPullParser parser)
6629 throws IOException, XmlPullParserException {
6630 int outerDepth = parser.getDepth();
6631 int type;
6632 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6633 && (type != XmlPullParser.END_TAG
6634 || parser.getDepth() > outerDepth)) {
6635 if (type == XmlPullParser.END_TAG
6636 || type == XmlPullParser.TEXT) {
6637 continue;
6638 }
6639
6640 String tagName = parser.getName();
6641 if (tagName.equals("item")) {
6642 String name = parser.getAttributeValue(null, "name");
6643 if (name != null) {
6644 packageSetting.disabledComponents.add(name.intern());
6645 } else {
6646 reportSettingsProblem(Log.WARN,
6647 "Error in package manager settings: <disabled-components> has"
6648 + " no name at " + parser.getPositionDescription());
6649 }
6650 } else {
6651 reportSettingsProblem(Log.WARN,
6652 "Unknown element under <disabled-components>: "
6653 + parser.getName());
6654 }
6655 XmlUtils.skipCurrentTag(parser);
6656 }
6657 }
6658
6659 private void readEnabledComponentsLP(PackageSettingBase packageSetting,
6660 XmlPullParser parser)
6661 throws IOException, XmlPullParserException {
6662 int outerDepth = parser.getDepth();
6663 int type;
6664 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6665 && (type != XmlPullParser.END_TAG
6666 || parser.getDepth() > outerDepth)) {
6667 if (type == XmlPullParser.END_TAG
6668 || type == XmlPullParser.TEXT) {
6669 continue;
6670 }
6671
6672 String tagName = parser.getName();
6673 if (tagName.equals("item")) {
6674 String name = parser.getAttributeValue(null, "name");
6675 if (name != null) {
6676 packageSetting.enabledComponents.add(name.intern());
6677 } else {
6678 reportSettingsProblem(Log.WARN,
6679 "Error in package manager settings: <enabled-components> has"
6680 + " no name at " + parser.getPositionDescription());
6681 }
6682 } else {
6683 reportSettingsProblem(Log.WARN,
6684 "Unknown element under <enabled-components>: "
6685 + parser.getName());
6686 }
6687 XmlUtils.skipCurrentTag(parser);
6688 }
6689 }
6690
6691 private void readSharedUserLP(XmlPullParser parser)
6692 throws XmlPullParserException, IOException {
6693 String name = null;
6694 String idStr = null;
6695 int pkgFlags = 0;
6696 SharedUserSetting su = null;
6697 try {
6698 name = parser.getAttributeValue(null, "name");
6699 idStr = parser.getAttributeValue(null, "userId");
6700 int userId = idStr != null ? Integer.parseInt(idStr) : 0;
6701 if ("true".equals(parser.getAttributeValue(null, "system"))) {
6702 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6703 }
6704 if (name == null) {
6705 reportSettingsProblem(Log.WARN,
6706 "Error in package manager settings: <shared-user> has no name at "
6707 + parser.getPositionDescription());
6708 } else if (userId == 0) {
6709 reportSettingsProblem(Log.WARN,
6710 "Error in package manager settings: shared-user "
6711 + name + " has bad userId " + idStr + " at "
6712 + parser.getPositionDescription());
6713 } else {
6714 if ((su=addSharedUserLP(name.intern(), userId, pkgFlags)) == null) {
6715 reportSettingsProblem(Log.ERROR,
6716 "Occurred while parsing settings at "
6717 + parser.getPositionDescription());
6718 }
6719 }
6720 } catch (NumberFormatException e) {
6721 reportSettingsProblem(Log.WARN,
6722 "Error in package manager settings: package "
6723 + name + " has bad userId " + idStr + " at "
6724 + parser.getPositionDescription());
6725 };
6726
6727 if (su != null) {
6728 int outerDepth = parser.getDepth();
6729 int type;
6730 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6731 && (type != XmlPullParser.END_TAG
6732 || parser.getDepth() > outerDepth)) {
6733 if (type == XmlPullParser.END_TAG
6734 || type == XmlPullParser.TEXT) {
6735 continue;
6736 }
6737
6738 String tagName = parser.getName();
6739 if (tagName.equals("sigs")) {
6740 su.signatures.readXml(parser, mPastSignatures);
6741 } else if (tagName.equals("perms")) {
6742 readGrantedPermissionsLP(parser, su.loadedPermissions);
6743 } else {
6744 reportSettingsProblem(Log.WARN,
6745 "Unknown element under <shared-user>: "
6746 + parser.getName());
6747 XmlUtils.skipCurrentTag(parser);
6748 }
6749 }
6750
6751 } else {
6752 XmlUtils.skipCurrentTag(parser);
6753 }
6754 }
6755
6756 private void readGrantedPermissionsLP(XmlPullParser parser,
6757 HashSet<String> outPerms) throws IOException, XmlPullParserException {
6758 int outerDepth = parser.getDepth();
6759 int type;
6760 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6761 && (type != XmlPullParser.END_TAG
6762 || parser.getDepth() > outerDepth)) {
6763 if (type == XmlPullParser.END_TAG
6764 || type == XmlPullParser.TEXT) {
6765 continue;
6766 }
6767
6768 String tagName = parser.getName();
6769 if (tagName.equals("item")) {
6770 String name = parser.getAttributeValue(null, "name");
6771 if (name != null) {
6772 outPerms.add(name.intern());
6773 } else {
6774 reportSettingsProblem(Log.WARN,
6775 "Error in package manager settings: <perms> has"
6776 + " no name at " + parser.getPositionDescription());
6777 }
6778 } else {
6779 reportSettingsProblem(Log.WARN,
6780 "Unknown element under <perms>: "
6781 + parser.getName());
6782 }
6783 XmlUtils.skipCurrentTag(parser);
6784 }
6785 }
6786
6787 private void readPreferredPackagesLP(XmlPullParser parser)
6788 throws XmlPullParserException, IOException {
6789 int outerDepth = parser.getDepth();
6790 int type;
6791 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6792 && (type != XmlPullParser.END_TAG
6793 || parser.getDepth() > outerDepth)) {
6794 if (type == XmlPullParser.END_TAG
6795 || type == XmlPullParser.TEXT) {
6796 continue;
6797 }
6798
6799 String tagName = parser.getName();
6800 if (tagName.equals("item")) {
6801 String name = parser.getAttributeValue(null, "name");
6802 if (name != null) {
6803 mPendingPreferredPackages.add(name);
6804 } else {
6805 reportSettingsProblem(Log.WARN,
6806 "Error in package manager settings: <preferred-package> has no name at "
6807 + parser.getPositionDescription());
6808 }
6809 } else {
6810 reportSettingsProblem(Log.WARN,
6811 "Unknown element under <preferred-packages>: "
6812 + parser.getName());
6813 }
6814 XmlUtils.skipCurrentTag(parser);
6815 }
6816 }
6817
6818 private void readPreferredActivitiesLP(XmlPullParser parser)
6819 throws XmlPullParserException, IOException {
6820 int outerDepth = parser.getDepth();
6821 int type;
6822 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6823 && (type != XmlPullParser.END_TAG
6824 || parser.getDepth() > outerDepth)) {
6825 if (type == XmlPullParser.END_TAG
6826 || type == XmlPullParser.TEXT) {
6827 continue;
6828 }
6829
6830 String tagName = parser.getName();
6831 if (tagName.equals("item")) {
6832 PreferredActivity pa = new PreferredActivity(parser);
6833 if (pa.mParseError == null) {
6834 mPreferredActivities.addFilter(pa);
6835 } else {
6836 reportSettingsProblem(Log.WARN,
6837 "Error in package manager settings: <preferred-activity> "
6838 + pa.mParseError + " at "
6839 + parser.getPositionDescription());
6840 }
6841 } else {
6842 reportSettingsProblem(Log.WARN,
6843 "Unknown element under <preferred-activities>: "
6844 + parser.getName());
6845 XmlUtils.skipCurrentTag(parser);
6846 }
6847 }
6848 }
6849
6850 // Returns -1 if we could not find an available UserId to assign
6851 private int newUserIdLP(Object obj) {
6852 // Let's be stupidly inefficient for now...
6853 final int N = mUserIds.size();
6854 for (int i=0; i<N; i++) {
6855 if (mUserIds.get(i) == null) {
6856 mUserIds.set(i, obj);
6857 return FIRST_APPLICATION_UID + i;
6858 }
6859 }
6860
6861 // None left?
6862 if (N >= MAX_APPLICATION_UIDS) {
6863 return -1;
6864 }
6865
6866 mUserIds.add(obj);
6867 return FIRST_APPLICATION_UID + N;
6868 }
6869
6870 public PackageSetting getDisabledSystemPkg(String name) {
6871 synchronized(mPackages) {
6872 PackageSetting ps = mDisabledSysPackages.get(name);
6873 return ps;
6874 }
6875 }
6876
6877 boolean isEnabledLP(ComponentInfo componentInfo, int flags) {
6878 final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
6879 if (Config.LOGV) {
6880 Log.v(TAG, "isEnabledLock - packageName = " + componentInfo.packageName
6881 + " componentName = " + componentInfo.name);
6882 Log.v(TAG, "enabledComponents: "
6883 + Arrays.toString(packageSettings.enabledComponents.toArray()));
6884 Log.v(TAG, "disabledComponents: "
6885 + Arrays.toString(packageSettings.disabledComponents.toArray()));
6886 }
6887 return ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0)
6888 || ((componentInfo.enabled
6889 && ((packageSettings.enabled == COMPONENT_ENABLED_STATE_ENABLED)
6890 || (componentInfo.applicationInfo.enabled
6891 && packageSettings.enabled != COMPONENT_ENABLED_STATE_DISABLED))
6892 && !packageSettings.disabledComponents.contains(componentInfo.name))
6893 || packageSettings.enabledComponents.contains(componentInfo.name));
6894 }
6895 }
6896}