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