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