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