blob: f51f3d02e4d123959907910aaa96258f931eee12 [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
Mihai Predaeae850c2009-05-13 10:13:48 +02001272 private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
1273 int flags, List<ResolveInfo> query) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 if (query != null) {
1275 final int N = query.size();
1276 if (N == 1) {
1277 return query.get(0);
1278 } else if (N > 1) {
1279 // If there is more than one activity with the same priority,
1280 // then let the user decide between them.
1281 ResolveInfo r0 = query.get(0);
1282 ResolveInfo r1 = query.get(1);
1283 if (false) {
1284 System.out.println(r0.activityInfo.name +
1285 "=" + r0.priority + " vs " +
1286 r1.activityInfo.name +
1287 "=" + r1.priority);
1288 }
1289 // If the first activity has a higher priority, or a different
1290 // default, then it is always desireable to pick it.
1291 if (r0.priority != r1.priority
1292 || r0.preferredOrder != r1.preferredOrder
1293 || r0.isDefault != r1.isDefault) {
1294 return query.get(0);
1295 }
1296 // If we have saved a preference for a preferred activity for
1297 // this Intent, use that.
1298 ResolveInfo ri = findPreferredActivity(intent, resolvedType,
1299 flags, query, r0.priority);
1300 if (ri != null) {
1301 return ri;
1302 }
1303 return mResolveInfo;
1304 }
1305 }
1306 return null;
1307 }
1308
1309 ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
1310 int flags, List<ResolveInfo> query, int priority) {
1311 synchronized (mPackages) {
1312 if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
1313 List<PreferredActivity> prefs =
Mihai Preda074edef2009-05-18 17:13:31 +02001314 mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
1316 if (prefs != null && prefs.size() > 0) {
1317 // First figure out how good the original match set is.
1318 // We will only allow preferred activities that came
1319 // from the same match quality.
1320 int match = 0;
1321 final int N = query.size();
1322 if (DEBUG_PREFERRED) Log.v(TAG, "Figuring out best match...");
1323 for (int j=0; j<N; j++) {
1324 ResolveInfo ri = query.get(j);
1325 if (DEBUG_PREFERRED) Log.v(TAG, "Match for " + ri.activityInfo
1326 + ": 0x" + Integer.toHexString(match));
1327 if (ri.match > match) match = ri.match;
1328 }
1329 if (DEBUG_PREFERRED) Log.v(TAG, "Best match: 0x"
1330 + Integer.toHexString(match));
1331 match &= IntentFilter.MATCH_CATEGORY_MASK;
1332 final int M = prefs.size();
1333 for (int i=0; i<M; i++) {
1334 PreferredActivity pa = prefs.get(i);
1335 if (pa.mMatch != match) {
1336 continue;
1337 }
1338 ActivityInfo ai = getActivityInfo(pa.mActivity, flags);
1339 if (DEBUG_PREFERRED) {
1340 Log.v(TAG, "Got preferred activity:");
1341 ai.dump(new LogPrinter(Log.INFO, TAG), " ");
1342 }
1343 if (ai != null) {
1344 for (int j=0; j<N; j++) {
1345 ResolveInfo ri = query.get(j);
1346 if (!ri.activityInfo.applicationInfo.packageName
1347 .equals(ai.applicationInfo.packageName)) {
1348 continue;
1349 }
1350 if (!ri.activityInfo.name.equals(ai.name)) {
1351 continue;
1352 }
1353
1354 // Okay we found a previously set preferred app.
1355 // If the result set is different from when this
1356 // was created, we need to clear it and re-ask the
1357 // user their preference.
1358 if (!pa.sameSet(query, priority)) {
1359 Log.i(TAG, "Result set changed, dropping preferred activity for "
1360 + intent + " type " + resolvedType);
1361 mSettings.mPreferredActivities.removeFilter(pa);
1362 return null;
1363 }
1364
1365 // Yay!
1366 return ri;
1367 }
1368 }
1369 }
1370 }
1371 }
1372 return null;
1373 }
1374
1375 public List<ResolveInfo> queryIntentActivities(Intent intent,
1376 String resolvedType, int flags) {
1377 ComponentName comp = intent.getComponent();
1378 if (comp != null) {
1379 List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
1380 ActivityInfo ai = getActivityInfo(comp, flags);
1381 if (ai != null) {
1382 ResolveInfo ri = new ResolveInfo();
1383 ri.activityInfo = ai;
1384 list.add(ri);
1385 }
1386 return list;
1387 }
1388
1389 synchronized (mPackages) {
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07001390 String pkgName = intent.getPackage();
1391 if (pkgName == null) {
1392 return (List<ResolveInfo>)mActivities.queryIntent(intent,
1393 resolvedType, flags);
1394 }
1395 PackageParser.Package pkg = mPackages.get(pkgName);
1396 if (pkg != null) {
1397 return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent,
1398 resolvedType, flags, pkg.activities);
1399 }
1400 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 }
1402 }
1403
1404 public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
1405 Intent[] specifics, String[] specificTypes, Intent intent,
1406 String resolvedType, int flags) {
1407 final String resultsAction = intent.getAction();
1408
1409 List<ResolveInfo> results = queryIntentActivities(
1410 intent, resolvedType, flags|PackageManager.GET_RESOLVED_FILTER);
1411 if (Config.LOGV) Log.v(TAG, "Query " + intent + ": " + results);
1412
1413 int specificsPos = 0;
1414 int N;
1415
1416 // todo: note that the algorithm used here is O(N^2). This
1417 // isn't a problem in our current environment, but if we start running
1418 // into situations where we have more than 5 or 10 matches then this
1419 // should probably be changed to something smarter...
1420
1421 // First we go through and resolve each of the specific items
1422 // that were supplied, taking care of removing any corresponding
1423 // duplicate items in the generic resolve list.
1424 if (specifics != null) {
1425 for (int i=0; i<specifics.length; i++) {
1426 final Intent sintent = specifics[i];
1427 if (sintent == null) {
1428 continue;
1429 }
1430
1431 if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + sintent);
1432 String action = sintent.getAction();
1433 if (resultsAction != null && resultsAction.equals(action)) {
1434 // If this action was explicitly requested, then don't
1435 // remove things that have it.
1436 action = null;
1437 }
1438 ComponentName comp = sintent.getComponent();
1439 ResolveInfo ri = null;
1440 ActivityInfo ai = null;
1441 if (comp == null) {
1442 ri = resolveIntent(
1443 sintent,
1444 specificTypes != null ? specificTypes[i] : null,
1445 flags);
1446 if (ri == null) {
1447 continue;
1448 }
1449 if (ri == mResolveInfo) {
1450 // ACK! Must do something better with this.
1451 }
1452 ai = ri.activityInfo;
1453 comp = new ComponentName(ai.applicationInfo.packageName,
1454 ai.name);
1455 } else {
1456 ai = getActivityInfo(comp, flags);
1457 if (ai == null) {
1458 continue;
1459 }
1460 }
1461
1462 // Look for any generic query activities that are duplicates
1463 // of this specific one, and remove them from the results.
1464 if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + ai);
1465 N = results.size();
1466 int j;
1467 for (j=specificsPos; j<N; j++) {
1468 ResolveInfo sri = results.get(j);
1469 if ((sri.activityInfo.name.equals(comp.getClassName())
1470 && sri.activityInfo.applicationInfo.packageName.equals(
1471 comp.getPackageName()))
1472 || (action != null && sri.filter.matchAction(action))) {
1473 results.remove(j);
1474 if (Config.LOGV) Log.v(
1475 TAG, "Removing duplicate item from " + j
1476 + " due to specific " + specificsPos);
1477 if (ri == null) {
1478 ri = sri;
1479 }
1480 j--;
1481 N--;
1482 }
1483 }
1484
1485 // Add this specific item to its proper place.
1486 if (ri == null) {
1487 ri = new ResolveInfo();
1488 ri.activityInfo = ai;
1489 }
1490 results.add(specificsPos, ri);
1491 ri.specificIndex = i;
1492 specificsPos++;
1493 }
1494 }
1495
1496 // Now we go through the remaining generic results and remove any
1497 // duplicate actions that are found here.
1498 N = results.size();
1499 for (int i=specificsPos; i<N-1; i++) {
1500 final ResolveInfo rii = results.get(i);
1501 if (rii.filter == null) {
1502 continue;
1503 }
1504
1505 // Iterate over all of the actions of this result's intent
1506 // filter... typically this should be just one.
1507 final Iterator<String> it = rii.filter.actionsIterator();
1508 if (it == null) {
1509 continue;
1510 }
1511 while (it.hasNext()) {
1512 final String action = it.next();
1513 if (resultsAction != null && resultsAction.equals(action)) {
1514 // If this action was explicitly requested, then don't
1515 // remove things that have it.
1516 continue;
1517 }
1518 for (int j=i+1; j<N; j++) {
1519 final ResolveInfo rij = results.get(j);
1520 if (rij.filter != null && rij.filter.hasAction(action)) {
1521 results.remove(j);
1522 if (Config.LOGV) Log.v(
1523 TAG, "Removing duplicate item from " + j
1524 + " due to action " + action + " at " + i);
1525 j--;
1526 N--;
1527 }
1528 }
1529 }
1530
1531 // If the caller didn't request filter information, drop it now
1532 // so we don't have to marshall/unmarshall it.
1533 if ((flags&PackageManager.GET_RESOLVED_FILTER) == 0) {
1534 rii.filter = null;
1535 }
1536 }
1537
1538 // Filter out the caller activity if so requested.
1539 if (caller != null) {
1540 N = results.size();
1541 for (int i=0; i<N; i++) {
1542 ActivityInfo ainfo = results.get(i).activityInfo;
1543 if (caller.getPackageName().equals(ainfo.applicationInfo.packageName)
1544 && caller.getClassName().equals(ainfo.name)) {
1545 results.remove(i);
1546 break;
1547 }
1548 }
1549 }
1550
1551 // If the caller didn't request filter information,
1552 // drop them now so we don't have to
1553 // marshall/unmarshall it.
1554 if ((flags&PackageManager.GET_RESOLVED_FILTER) == 0) {
1555 N = results.size();
1556 for (int i=0; i<N; i++) {
1557 results.get(i).filter = null;
1558 }
1559 }
1560
1561 if (Config.LOGV) Log.v(TAG, "Result: " + results);
1562 return results;
1563 }
1564
1565 public List<ResolveInfo> queryIntentReceivers(Intent intent,
1566 String resolvedType, int flags) {
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07001567 ComponentName comp = intent.getComponent();
1568 if (comp != null) {
1569 List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
1570 ActivityInfo ai = getReceiverInfo(comp, flags);
1571 if (ai != null) {
1572 ResolveInfo ri = new ResolveInfo();
1573 ri.activityInfo = ai;
1574 list.add(ri);
1575 }
1576 return list;
1577 }
1578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 synchronized (mPackages) {
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07001580 String pkgName = intent.getPackage();
1581 if (pkgName == null) {
1582 return (List<ResolveInfo>)mReceivers.queryIntent(intent,
1583 resolvedType, flags);
1584 }
1585 PackageParser.Package pkg = mPackages.get(pkgName);
1586 if (pkg != null) {
1587 return (List<ResolveInfo>) mReceivers.queryIntentForPackage(intent,
1588 resolvedType, flags, pkg.receivers);
1589 }
1590 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 }
1592 }
1593
1594 public ResolveInfo resolveService(Intent intent, String resolvedType,
1595 int flags) {
1596 List<ResolveInfo> query = queryIntentServices(intent, resolvedType,
1597 flags);
1598 if (query != null) {
1599 if (query.size() >= 1) {
1600 // If there is more than one service with the same priority,
1601 // just arbitrarily pick the first one.
1602 return query.get(0);
1603 }
1604 }
1605 return null;
1606 }
1607
1608 public List<ResolveInfo> queryIntentServices(Intent intent,
1609 String resolvedType, int flags) {
1610 ComponentName comp = intent.getComponent();
1611 if (comp != null) {
1612 List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
1613 ServiceInfo si = getServiceInfo(comp, flags);
1614 if (si != null) {
1615 ResolveInfo ri = new ResolveInfo();
1616 ri.serviceInfo = si;
1617 list.add(ri);
1618 }
1619 return list;
1620 }
1621
1622 synchronized (mPackages) {
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07001623 String pkgName = intent.getPackage();
1624 if (pkgName == null) {
1625 return (List<ResolveInfo>)mServices.queryIntent(intent,
1626 resolvedType, flags);
1627 }
1628 PackageParser.Package pkg = mPackages.get(pkgName);
1629 if (pkg != null) {
1630 return (List<ResolveInfo>)mServices.queryIntentForPackage(intent,
1631 resolvedType, flags, pkg.services);
1632 }
1633 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 }
1635 }
1636
1637 public List<PackageInfo> getInstalledPackages(int flags) {
1638 ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
1639
1640 synchronized (mPackages) {
1641 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1642 Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
1643 while (i.hasNext()) {
1644 final PackageSetting ps = i.next();
1645 PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags);
1646 if(psPkg != null) {
1647 finalList.add(psPkg);
1648 }
1649 }
1650 }
1651 else {
1652 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1653 while (i.hasNext()) {
1654 final PackageParser.Package p = i.next();
1655 if (p.applicationInfo != null) {
1656 PackageInfo pi = generatePackageInfo(p, flags);
1657 if(pi != null) {
1658 finalList.add(pi);
1659 }
1660 }
1661 }
1662 }
1663 }
1664 return finalList;
1665 }
1666
1667 public List<ApplicationInfo> getInstalledApplications(int flags) {
1668 ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
1669 synchronized(mPackages) {
1670 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1671 Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
1672 while (i.hasNext()) {
1673 final PackageSetting ps = i.next();
1674 ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags);
1675 if(ai != null) {
1676 finalList.add(ai);
1677 }
1678 }
1679 }
1680 else {
1681 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1682 while (i.hasNext()) {
1683 final PackageParser.Package p = i.next();
1684 if (p.applicationInfo != null) {
1685 ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags);
1686 if(ai != null) {
1687 finalList.add(ai);
1688 }
1689 }
1690 }
1691 }
1692 }
1693 return finalList;
1694 }
1695
1696 public List<ApplicationInfo> getPersistentApplications(int flags) {
1697 ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
1698
1699 synchronized (mPackages) {
1700 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1701 while (i.hasNext()) {
1702 PackageParser.Package p = i.next();
1703 if (p.applicationInfo != null
1704 && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
1705 && (!mSafeMode || (p.applicationInfo.flags
1706 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
1707 finalList.add(p.applicationInfo);
1708 }
1709 }
1710 }
1711
1712 return finalList;
1713 }
1714
1715 public ProviderInfo resolveContentProvider(String name, int flags) {
1716 synchronized (mPackages) {
1717 final PackageParser.Provider provider = mProviders.get(name);
1718 return provider != null
1719 && mSettings.isEnabledLP(provider.info, flags)
1720 && (!mSafeMode || (provider.info.applicationInfo.flags
1721 &ApplicationInfo.FLAG_SYSTEM) != 0)
1722 ? PackageParser.generateProviderInfo(provider, flags)
1723 : null;
1724 }
1725 }
1726
1727 public void querySyncProviders(List outNames, List outInfo) {
1728 synchronized (mPackages) {
1729 Iterator<Map.Entry<String, PackageParser.Provider>> i
1730 = mProviders.entrySet().iterator();
1731
1732 while (i.hasNext()) {
1733 Map.Entry<String, PackageParser.Provider> entry = i.next();
1734 PackageParser.Provider p = entry.getValue();
1735
1736 if (p.syncable
1737 && (!mSafeMode || (p.info.applicationInfo.flags
1738 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
1739 outNames.add(entry.getKey());
1740 outInfo.add(PackageParser.generateProviderInfo(p, 0));
1741 }
1742 }
1743 }
1744 }
1745
1746 public List<ProviderInfo> queryContentProviders(String processName,
1747 int uid, int flags) {
1748 ArrayList<ProviderInfo> finalList = null;
1749
1750 synchronized (mPackages) {
1751 Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
1752 while (i.hasNext()) {
1753 PackageParser.Provider p = i.next();
1754 if (p.info.authority != null
1755 && (processName == null ||
1756 (p.info.processName.equals(processName)
1757 && p.info.applicationInfo.uid == uid))
1758 && mSettings.isEnabledLP(p.info, flags)
1759 && (!mSafeMode || (p.info.applicationInfo.flags
1760 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
1761 if (finalList == null) {
1762 finalList = new ArrayList<ProviderInfo>(3);
1763 }
1764 finalList.add(PackageParser.generateProviderInfo(p,
1765 flags));
1766 }
1767 }
1768 }
1769
1770 if (finalList != null) {
1771 Collections.sort(finalList, mProviderInitOrderSorter);
1772 }
1773
1774 return finalList;
1775 }
1776
1777 public InstrumentationInfo getInstrumentationInfo(ComponentName name,
1778 int flags) {
1779 synchronized (mPackages) {
1780 final PackageParser.Instrumentation i = mInstrumentation.get(name);
1781 return PackageParser.generateInstrumentationInfo(i, flags);
1782 }
1783 }
1784
1785 public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
1786 int flags) {
1787 ArrayList<InstrumentationInfo> finalList =
1788 new ArrayList<InstrumentationInfo>();
1789
1790 synchronized (mPackages) {
1791 Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
1792 while (i.hasNext()) {
1793 PackageParser.Instrumentation p = i.next();
1794 if (targetPackage == null
1795 || targetPackage.equals(p.info.targetPackage)) {
1796 finalList.add(PackageParser.generateInstrumentationInfo(p,
1797 flags));
1798 }
1799 }
1800 }
1801
1802 return finalList;
1803 }
1804
1805 private void scanDirLI(File dir, int flags, int scanMode) {
1806 Log.d(TAG, "Scanning app dir " + dir);
1807
1808 String[] files = dir.list();
1809
1810 int i;
1811 for (i=0; i<files.length; i++) {
1812 File file = new File(dir, files[i]);
1813 PackageParser.Package pkg = scanPackageLI(file, file, file,
1814 flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
1815 }
1816 }
1817
1818 private static void reportSettingsProblem(int priority, String msg) {
1819 try {
1820 File dataDir = Environment.getDataDirectory();
1821 File systemDir = new File(dataDir, "system");
1822 File fname = new File(systemDir, "uiderrors.txt");
1823 FileOutputStream out = new FileOutputStream(fname, true);
1824 PrintWriter pw = new PrintWriter(out);
1825 pw.println(msg);
1826 pw.close();
1827 FileUtils.setPermissions(
1828 fname.toString(),
1829 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
1830 -1, -1);
1831 } catch (java.io.IOException e) {
1832 }
1833 Log.println(priority, TAG, msg);
1834 }
1835
1836 private boolean collectCertificatesLI(PackageParser pp, PackageSetting ps,
1837 PackageParser.Package pkg, File srcFile, int parseFlags) {
1838 if (GET_CERTIFICATES) {
1839 if (ps == null || !ps.codePath.equals(srcFile)
1840 || ps.getTimeStamp() != srcFile.lastModified()) {
1841 Log.i(TAG, srcFile.toString() + " changed; collecting certs");
1842 if (!pp.collectCertificates(pkg, parseFlags)) {
1843 mLastScanError = pp.getParseError();
1844 return false;
1845 }
1846 }
1847 }
1848 return true;
1849 }
1850
1851 /*
1852 * Scan a package and return the newly parsed package.
1853 * Returns null in case of errors and the error code is stored in mLastScanError
1854 */
1855 private PackageParser.Package scanPackageLI(File scanFile,
1856 File destCodeFile, File destResourceFile, int parseFlags,
1857 int scanMode) {
1858 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
1859 parseFlags |= mDefParseFlags;
1860 PackageParser pp = new PackageParser(scanFile.getPath());
1861 pp.setSeparateProcesses(mSeparateProcesses);
Dianne Hackborn851a5412009-05-08 12:06:44 -07001862 pp.setSdkVersion(mSdkVersion, mSdkCodename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 final PackageParser.Package pkg = pp.parsePackage(scanFile,
1864 destCodeFile.getAbsolutePath(), mMetrics, parseFlags);
1865 if (pkg == null) {
1866 mLastScanError = pp.getParseError();
1867 return null;
1868 }
1869 PackageSetting ps;
1870 PackageSetting updatedPkg;
1871 synchronized (mPackages) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07001872 ps = mSettings.peekPackageLP(pkg.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName);
1874 }
1875 if (updatedPkg != null) {
1876 // An updated system app will not have the PARSE_IS_SYSTEM flag set initially
1877 parseFlags |= PackageParser.PARSE_IS_SYSTEM;
1878 }
1879 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
1880 // Check for updated system applications here
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07001881 if (updatedPkg != null) {
1882 if ((ps != null) && (!ps.codePath.getPath().equals(scanFile.getPath()))) {
1883 if (pkg.mVersionCode <= ps.versionCode) {
1884 // The system package has been updated and the code path does not match
1885 // Ignore entry. Just return
1886 Log.w(TAG, "Package:" + pkg.packageName +
1887 " has been updated. Ignoring the one from path:"+scanFile);
1888 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
1889 return null;
1890 } else {
1891 // Delete the older apk pointed to by ps
1892 deletePackageResourcesLI(ps.name, ps.codePathString, ps.resourcePathString);
1893 mSettings.enableSystemPackageLP(ps.name);
1894 }
1895 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 }
1897 }
1898 if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
1899 Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
1900 return null;
1901 }
1902 // The apk is forward locked (not public) if its code and resources
1903 // are kept in different files.
1904 if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
1905 scanMode |= SCAN_FORWARD_LOCKED;
1906 }
1907 // Note that we invoke the following method only if we are about to unpack an application
1908 return scanPackageLI(scanFile, destCodeFile, destResourceFile,
1909 pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
1910 }
1911
1912 private static String fixProcessName(String defProcessName,
1913 String processName, int uid) {
1914 if (processName == null) {
1915 return defProcessName;
1916 }
1917 return processName;
1918 }
1919
1920 private boolean verifySignaturesLP(PackageSetting pkgSetting,
1921 PackageParser.Package pkg, int parseFlags, boolean updateSignature) {
1922 if (pkg.mSignatures != null) {
1923 if (!pkgSetting.signatures.updateSignatures(pkg.mSignatures,
1924 updateSignature)) {
1925 Log.e(TAG, "Package " + pkg.packageName
1926 + " signatures do not match the previously installed version; ignoring!");
1927 mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
1928 return false;
1929 }
1930
1931 if (pkgSetting.sharedUser != null) {
1932 if (!pkgSetting.sharedUser.signatures.mergeSignatures(
1933 pkg.mSignatures, updateSignature)) {
1934 Log.e(TAG, "Package " + pkg.packageName
1935 + " has no signatures that match those in shared user "
1936 + pkgSetting.sharedUser.name + "; ignoring!");
1937 mLastScanError = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
1938 return false;
1939 }
1940 }
1941 } else {
1942 pkg.mSignatures = pkgSetting.signatures.mSignatures;
1943 }
1944 return true;
1945 }
1946
1947 private PackageParser.Package scanPackageLI(
1948 File scanFile, File destCodeFile, File destResourceFile,
1949 PackageParser.Package pkg, int parseFlags, int scanMode) {
1950
1951 mScanningPath = scanFile;
1952 if (pkg == null) {
1953 mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1954 return null;
1955 }
1956
1957 final String pkgName = pkg.applicationInfo.packageName;
1958 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
1959 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
1960 }
1961
1962 if (pkgName.equals("android")) {
1963 synchronized (mPackages) {
1964 if (mAndroidApplication != null) {
1965 Log.w(TAG, "*************************************************");
1966 Log.w(TAG, "Core android package being redefined. Skipping.");
1967 Log.w(TAG, " file=" + mScanningPath);
1968 Log.w(TAG, "*************************************************");
1969 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
1970 return null;
1971 }
1972
1973 // Set up information for our fall-back user intent resolution
1974 // activity.
1975 mPlatformPackage = pkg;
1976 pkg.mVersionCode = mSdkVersion;
1977 mAndroidApplication = pkg.applicationInfo;
1978 mResolveActivity.applicationInfo = mAndroidApplication;
1979 mResolveActivity.name = ResolverActivity.class.getName();
1980 mResolveActivity.packageName = mAndroidApplication.packageName;
1981 mResolveActivity.processName = mAndroidApplication.processName;
1982 mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
1983 mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
1984 mResolveActivity.theme = com.android.internal.R.style.Theme_Dialog_Alert;
1985 mResolveActivity.exported = true;
1986 mResolveActivity.enabled = true;
1987 mResolveInfo.activityInfo = mResolveActivity;
1988 mResolveInfo.priority = 0;
1989 mResolveInfo.preferredOrder = 0;
1990 mResolveInfo.match = 0;
1991 mResolveComponentName = new ComponentName(
1992 mAndroidApplication.packageName, mResolveActivity.name);
1993 }
1994 }
1995
1996 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
1997 TAG, "Scanning package " + pkgName);
1998 if (mPackages.containsKey(pkgName) || mSharedLibraries.containsKey(pkgName)) {
1999 Log.w(TAG, "*************************************************");
2000 Log.w(TAG, "Application package " + pkgName
2001 + " already installed. Skipping duplicate.");
2002 Log.w(TAG, "*************************************************");
2003 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
2004 return null;
2005 }
2006
2007 SharedUserSetting suid = null;
2008 PackageSetting pkgSetting = null;
2009
2010 boolean removeExisting = false;
2011
2012 synchronized (mPackages) {
2013 // Check all shared libraries and map to their actual file path.
2014 if (pkg.usesLibraryFiles != null) {
2015 for (int i=0; i<pkg.usesLibraryFiles.length; i++) {
2016 String file = mSharedLibraries.get(pkg.usesLibraryFiles[i]);
2017 if (file == null) {
2018 Log.e(TAG, "Package " + pkg.packageName
2019 + " requires unavailable shared library "
2020 + pkg.usesLibraryFiles[i] + "; ignoring!");
2021 mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
2022 return null;
2023 }
2024 pkg.usesLibraryFiles[i] = file;
2025 }
2026 }
2027
2028 if (pkg.mSharedUserId != null) {
2029 suid = mSettings.getSharedUserLP(pkg.mSharedUserId,
2030 pkg.applicationInfo.flags, true);
2031 if (suid == null) {
2032 Log.w(TAG, "Creating application package " + pkgName
2033 + " for shared user failed");
2034 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2035 return null;
2036 }
2037 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) {
2038 Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid="
2039 + suid.userId + "): packages=" + suid.packages);
2040 }
2041 }
2042
2043 // Just create the setting, don't add it yet
2044 pkgSetting = mSettings.getPackageLP(pkg, suid, destCodeFile,
2045 destResourceFile, pkg.applicationInfo.flags, true, false);
2046 if (pkgSetting == null) {
2047 Log.w(TAG, "Creating application package " + pkgName + " failed");
2048 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2049 return null;
2050 }
2051 if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
2052 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
2053 }
2054
2055 pkg.applicationInfo.uid = pkgSetting.userId;
2056 pkg.mExtras = pkgSetting;
2057
2058 if (!verifySignaturesLP(pkgSetting, pkg, parseFlags,
2059 (scanMode&SCAN_UPDATE_SIGNATURE) != 0)) {
2060 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) {
2061 mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
2062 return null;
2063 }
2064 // The signature has changed, but this package is in the system
2065 // image... let's recover!
Suchi Amalapurapuc4dd60f2009-03-24 21:10:53 -07002066 pkgSetting.signatures.mSignatures = pkg.mSignatures;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 // However... if this package is part of a shared user, but it
2068 // doesn't match the signature of the shared user, let's fail.
2069 // What this means is that you can't change the signatures
2070 // associated with an overall shared user, which doesn't seem all
2071 // that unreasonable.
2072 if (pkgSetting.sharedUser != null) {
2073 if (!pkgSetting.sharedUser.signatures.mergeSignatures(
2074 pkg.mSignatures, false)) {
2075 mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
2076 return null;
2077 }
2078 }
2079 removeExisting = true;
2080 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002081
2082 // Verify that this new package doesn't have any content providers
2083 // that conflict with existing packages. Only do this if the
2084 // package isn't already installed, since we don't want to break
2085 // things that are installed.
2086 if ((scanMode&SCAN_NEW_INSTALL) != 0) {
2087 int N = pkg.providers.size();
2088 int i;
2089 for (i=0; i<N; i++) {
2090 PackageParser.Provider p = pkg.providers.get(i);
2091 String names[] = p.info.authority.split(";");
2092 for (int j = 0; j < names.length; j++) {
2093 if (mProviders.containsKey(names[j])) {
2094 PackageParser.Provider other = mProviders.get(names[j]);
2095 Log.w(TAG, "Can't install because provider name " + names[j] +
2096 " (in package " + pkg.applicationInfo.packageName +
2097 ") is already used by "
2098 + ((other != null && other.component != null)
2099 ? other.component.getPackageName() : "?"));
2100 mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
2101 return null;
2102 }
2103 }
2104 }
2105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002106 }
2107
2108 if (removeExisting) {
2109 if (mInstaller != null) {
2110 int ret = mInstaller.remove(pkgName);
2111 if (ret != 0) {
2112 String msg = "System package " + pkg.packageName
2113 + " could not have data directory erased after signature change.";
2114 reportSettingsProblem(Log.WARN, msg);
2115 mLastScanError = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
2116 return null;
2117 }
2118 }
2119 Log.w(TAG, "System package " + pkg.packageName
2120 + " signature changed: existing data removed.");
2121 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
2122 }
2123
2124 long scanFileTime = scanFile.lastModified();
2125 final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
2126 final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp();
2127 pkg.applicationInfo.processName = fixProcessName(
2128 pkg.applicationInfo.packageName,
2129 pkg.applicationInfo.processName,
2130 pkg.applicationInfo.uid);
2131 pkg.applicationInfo.publicSourceDir = pkgSetting.resourcePathString;
2132
2133 File dataPath;
2134 if (mPlatformPackage == pkg) {
2135 // The system package is special.
2136 dataPath = new File (Environment.getDataDirectory(), "system");
2137 pkg.applicationInfo.dataDir = dataPath.getPath();
2138 } else {
2139 // This is a normal package, need to make its data directory.
2140 dataPath = new File(mAppDataDir, pkgName);
2141 if (dataPath.exists()) {
2142 mOutPermissions[1] = 0;
2143 FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
2144 if (mOutPermissions[1] == pkg.applicationInfo.uid
2145 || !Process.supportsProcesses()) {
2146 pkg.applicationInfo.dataDir = dataPath.getPath();
2147 } else {
2148 boolean recovered = false;
2149 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
2150 // If this is a system app, we can at least delete its
2151 // current data so the application will still work.
2152 if (mInstaller != null) {
2153 int ret = mInstaller.remove(pkgName);
2154 if(ret >= 0) {
2155 // Old data gone!
2156 String msg = "System package " + pkg.packageName
2157 + " has changed from uid: "
2158 + mOutPermissions[1] + " to "
2159 + pkg.applicationInfo.uid + "; old data erased";
2160 reportSettingsProblem(Log.WARN, msg);
2161 recovered = true;
2162
2163 // And now re-install the app.
2164 ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
2165 pkg.applicationInfo.uid);
2166 if (ret == -1) {
2167 // Ack should not happen!
2168 msg = "System package " + pkg.packageName
2169 + " could not have data directory re-created after delete.";
2170 reportSettingsProblem(Log.WARN, msg);
2171 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2172 return null;
2173 }
2174 }
2175 }
2176 if (!recovered) {
2177 mHasSystemUidErrors = true;
2178 }
2179 }
2180 if (!recovered) {
2181 pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
2182 + pkg.applicationInfo.uid + "/fs_"
2183 + mOutPermissions[1];
2184 String msg = "Package " + pkg.packageName
2185 + " has mismatched uid: "
2186 + mOutPermissions[1] + " on disk, "
2187 + pkg.applicationInfo.uid + " in settings";
2188 synchronized (mPackages) {
2189 if (!mReportedUidError) {
2190 mReportedUidError = true;
2191 msg = msg + "; read messages:\n"
2192 + mSettings.getReadMessagesLP();
2193 }
2194 reportSettingsProblem(Log.ERROR, msg);
2195 }
2196 }
2197 }
2198 pkg.applicationInfo.dataDir = dataPath.getPath();
2199 } else {
2200 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGV)
2201 Log.v(TAG, "Want this data dir: " + dataPath);
2202 //invoke installer to do the actual installation
2203 if (mInstaller != null) {
2204 int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
2205 pkg.applicationInfo.uid);
2206 if(ret < 0) {
2207 // Error from installer
2208 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2209 return null;
2210 }
2211 } else {
2212 dataPath.mkdirs();
2213 if (dataPath.exists()) {
2214 FileUtils.setPermissions(
2215 dataPath.toString(),
2216 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
2217 pkg.applicationInfo.uid, pkg.applicationInfo.uid);
2218 }
2219 }
2220 if (dataPath.exists()) {
2221 pkg.applicationInfo.dataDir = dataPath.getPath();
2222 } else {
2223 Log.w(TAG, "Unable to create data directory: " + dataPath);
2224 pkg.applicationInfo.dataDir = null;
2225 }
2226 }
2227 }
2228
2229 // Perform shared library installation and dex validation and
2230 // optimization, if this is not a system app.
2231 if (mInstaller != null) {
2232 String path = scanFile.getPath();
2233 if (scanFileNewer) {
2234 Log.i(TAG, path + " changed; unpacking");
Dianne Hackbornb1811182009-05-21 15:45:42 -07002235 int err = cachePackageSharedLibsLI(pkg, dataPath, scanFile);
2236 if (err != PackageManager.INSTALL_SUCCEEDED) {
2237 mLastScanError = err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238 return null;
2239 }
2240 }
2241
2242 if ((scanMode&SCAN_NO_DEX) == 0
2243 && (pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
2244 int ret = 0;
2245 try {
2246 if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
2247 ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
2248 (scanMode&SCAN_FORWARD_LOCKED) == 0);
2249 }
2250 } catch (FileNotFoundException e) {
2251 Log.w(TAG, "Apk not found for dexopt: " + path);
2252 ret = -1;
2253 } catch (IOException e) {
2254 Log.w(TAG, "Exception reading apk: " + path, e);
2255 ret = -1;
2256 }
2257 if (ret < 0) {
2258 //error from installer
2259 mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
2260 return null;
2261 }
2262 }
2263 }
2264
2265 if (mFactoryTest && pkg.requestedPermissions.contains(
2266 android.Manifest.permission.FACTORY_TEST)) {
2267 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
2268 }
2269
2270 if ((scanMode&SCAN_MONITOR) != 0) {
2271 pkg.mPath = destCodeFile.getAbsolutePath();
2272 mAppDirs.put(pkg.mPath, pkg);
2273 }
2274
2275 synchronized (mPackages) {
2276 // We don't expect installation to fail beyond this point
2277 // Add the new setting to mSettings
2278 mSettings.insertPackageSettingLP(pkgSetting, pkg.packageName, suid);
2279 // Add the new setting to mPackages
2280 mPackages.put(pkg.applicationInfo.packageName, pkg);
2281 int N = pkg.providers.size();
2282 StringBuilder r = null;
2283 int i;
2284 for (i=0; i<N; i++) {
2285 PackageParser.Provider p = pkg.providers.get(i);
2286 p.info.processName = fixProcessName(pkg.applicationInfo.processName,
2287 p.info.processName, pkg.applicationInfo.uid);
2288 mProvidersByComponent.put(new ComponentName(p.info.packageName,
2289 p.info.name), p);
2290 p.syncable = p.info.isSyncable;
2291 String names[] = p.info.authority.split(";");
2292 p.info.authority = null;
2293 for (int j = 0; j < names.length; j++) {
2294 if (j == 1 && p.syncable) {
2295 // We only want the first authority for a provider to possibly be
2296 // syncable, so if we already added this provider using a different
2297 // authority clear the syncable flag. We copy the provider before
2298 // changing it because the mProviders object contains a reference
2299 // to a provider that we don't want to change.
2300 // Only do this for the second authority since the resulting provider
2301 // object can be the same for all future authorities for this provider.
2302 p = new PackageParser.Provider(p);
2303 p.syncable = false;
2304 }
2305 if (!mProviders.containsKey(names[j])) {
2306 mProviders.put(names[j], p);
2307 if (p.info.authority == null) {
2308 p.info.authority = names[j];
2309 } else {
2310 p.info.authority = p.info.authority + ";" + names[j];
2311 }
2312 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD)
2313 Log.d(TAG, "Registered content provider: " + names[j] +
2314 ", className = " + p.info.name +
2315 ", isSyncable = " + p.info.isSyncable);
2316 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07002317 PackageParser.Provider other = mProviders.get(names[j]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002318 Log.w(TAG, "Skipping provider name " + names[j] +
2319 " (in package " + pkg.applicationInfo.packageName +
The Android Open Source Project10592532009-03-18 17:39:46 -07002320 "): name already used by "
2321 + ((other != null && other.component != null)
2322 ? other.component.getPackageName() : "?"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002323 }
2324 }
2325 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2326 if (r == null) {
2327 r = new StringBuilder(256);
2328 } else {
2329 r.append(' ');
2330 }
2331 r.append(p.info.name);
2332 }
2333 }
2334 if (r != null) {
2335 if (Config.LOGD) Log.d(TAG, " Providers: " + r);
2336 }
2337
2338 N = pkg.services.size();
2339 r = null;
2340 for (i=0; i<N; i++) {
2341 PackageParser.Service s = pkg.services.get(i);
2342 s.info.processName = fixProcessName(pkg.applicationInfo.processName,
2343 s.info.processName, pkg.applicationInfo.uid);
2344 mServices.addService(s);
2345 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2346 if (r == null) {
2347 r = new StringBuilder(256);
2348 } else {
2349 r.append(' ');
2350 }
2351 r.append(s.info.name);
2352 }
2353 }
2354 if (r != null) {
2355 if (Config.LOGD) Log.d(TAG, " Services: " + r);
2356 }
2357
2358 N = pkg.receivers.size();
2359 r = null;
2360 for (i=0; i<N; i++) {
2361 PackageParser.Activity a = pkg.receivers.get(i);
2362 a.info.processName = fixProcessName(pkg.applicationInfo.processName,
2363 a.info.processName, pkg.applicationInfo.uid);
2364 mReceivers.addActivity(a, "receiver");
2365 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2366 if (r == null) {
2367 r = new StringBuilder(256);
2368 } else {
2369 r.append(' ');
2370 }
2371 r.append(a.info.name);
2372 }
2373 }
2374 if (r != null) {
2375 if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
2376 }
2377
2378 N = pkg.activities.size();
2379 r = null;
2380 for (i=0; i<N; i++) {
2381 PackageParser.Activity a = pkg.activities.get(i);
2382 a.info.processName = fixProcessName(pkg.applicationInfo.processName,
2383 a.info.processName, pkg.applicationInfo.uid);
2384 mActivities.addActivity(a, "activity");
2385 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2386 if (r == null) {
2387 r = new StringBuilder(256);
2388 } else {
2389 r.append(' ');
2390 }
2391 r.append(a.info.name);
2392 }
2393 }
2394 if (r != null) {
2395 if (Config.LOGD) Log.d(TAG, " Activities: " + r);
2396 }
2397
2398 N = pkg.permissionGroups.size();
2399 r = null;
2400 for (i=0; i<N; i++) {
2401 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
2402 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
2403 if (cur == null) {
2404 mPermissionGroups.put(pg.info.name, pg);
2405 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2406 if (r == null) {
2407 r = new StringBuilder(256);
2408 } else {
2409 r.append(' ');
2410 }
2411 r.append(pg.info.name);
2412 }
2413 } else {
2414 Log.w(TAG, "Permission group " + pg.info.name + " from package "
2415 + pg.info.packageName + " ignored: original from "
2416 + cur.info.packageName);
2417 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2418 if (r == null) {
2419 r = new StringBuilder(256);
2420 } else {
2421 r.append(' ');
2422 }
2423 r.append("DUP:");
2424 r.append(pg.info.name);
2425 }
2426 }
2427 }
2428 if (r != null) {
2429 if (Config.LOGD) Log.d(TAG, " Permission Groups: " + r);
2430 }
2431
2432 N = pkg.permissions.size();
2433 r = null;
2434 for (i=0; i<N; i++) {
2435 PackageParser.Permission p = pkg.permissions.get(i);
2436 HashMap<String, BasePermission> permissionMap =
2437 p.tree ? mSettings.mPermissionTrees
2438 : mSettings.mPermissions;
2439 p.group = mPermissionGroups.get(p.info.group);
2440 if (p.info.group == null || p.group != null) {
2441 BasePermission bp = permissionMap.get(p.info.name);
2442 if (bp == null) {
2443 bp = new BasePermission(p.info.name, p.info.packageName,
2444 BasePermission.TYPE_NORMAL);
2445 permissionMap.put(p.info.name, bp);
2446 }
2447 if (bp.perm == null) {
2448 if (bp.sourcePackage == null
2449 || bp.sourcePackage.equals(p.info.packageName)) {
2450 BasePermission tree = findPermissionTreeLP(p.info.name);
2451 if (tree == null
2452 || tree.sourcePackage.equals(p.info.packageName)) {
2453 bp.perm = p;
2454 bp.uid = pkg.applicationInfo.uid;
2455 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2456 if (r == null) {
2457 r = new StringBuilder(256);
2458 } else {
2459 r.append(' ');
2460 }
2461 r.append(p.info.name);
2462 }
2463 } else {
2464 Log.w(TAG, "Permission " + p.info.name + " from package "
2465 + p.info.packageName + " ignored: base tree "
2466 + tree.name + " is from package "
2467 + tree.sourcePackage);
2468 }
2469 } else {
2470 Log.w(TAG, "Permission " + p.info.name + " from package "
2471 + p.info.packageName + " ignored: original from "
2472 + bp.sourcePackage);
2473 }
2474 } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2475 if (r == null) {
2476 r = new StringBuilder(256);
2477 } else {
2478 r.append(' ');
2479 }
2480 r.append("DUP:");
2481 r.append(p.info.name);
2482 }
2483 } else {
2484 Log.w(TAG, "Permission " + p.info.name + " from package "
2485 + p.info.packageName + " ignored: no group "
2486 + p.group);
2487 }
2488 }
2489 if (r != null) {
2490 if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
2491 }
2492
2493 N = pkg.instrumentation.size();
2494 r = null;
2495 for (i=0; i<N; i++) {
2496 PackageParser.Instrumentation a = pkg.instrumentation.get(i);
2497 a.info.packageName = pkg.applicationInfo.packageName;
2498 a.info.sourceDir = pkg.applicationInfo.sourceDir;
2499 a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
2500 a.info.dataDir = pkg.applicationInfo.dataDir;
2501 mInstrumentation.put(a.component, a);
2502 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2503 if (r == null) {
2504 r = new StringBuilder(256);
2505 } else {
2506 r.append(' ');
2507 }
2508 r.append(a.info.name);
2509 }
2510 }
2511 if (r != null) {
2512 if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
2513 }
2514
2515 pkgSetting.setTimeStamp(scanFileTime);
2516 }
2517
2518 return pkg;
2519 }
2520
Dianne Hackbornb1811182009-05-21 15:45:42 -07002521 private int cachePackageSharedLibsLI(PackageParser.Package pkg,
2522 File dataPath, File scanFile) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 File sharedLibraryDir = new File(dataPath.getPath() + "/lib");
Dianne Hackbornb1811182009-05-21 15:45:42 -07002524 final String sharedLibraryABI = Build.CPU_ABI;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002525 final String apkLibraryDirectory = "lib/" + sharedLibraryABI + "/";
2526 final String apkSharedLibraryPrefix = apkLibraryDirectory + "lib";
2527 final String sharedLibrarySuffix = ".so";
Dianne Hackbornb1811182009-05-21 15:45:42 -07002528 boolean hasNativeCode = false;
2529 boolean installedNativeCode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 try {
2531 ZipFile zipFile = new ZipFile(scanFile);
2532 Enumeration<ZipEntry> entries =
2533 (Enumeration<ZipEntry>) zipFile.entries();
2534
2535 while (entries.hasMoreElements()) {
2536 ZipEntry entry = entries.nextElement();
2537 if (entry.isDirectory()) {
Dianne Hackbornb1811182009-05-21 15:45:42 -07002538 if (!hasNativeCode && entry.getName().startsWith("lib")) {
2539 hasNativeCode = true;
2540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002541 continue;
2542 }
2543 String entryName = entry.getName();
Dianne Hackbornb1811182009-05-21 15:45:42 -07002544 if (entryName.startsWith("lib/")) {
2545 hasNativeCode = true;
2546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002547 if (! (entryName.startsWith(apkSharedLibraryPrefix)
2548 && entryName.endsWith(sharedLibrarySuffix))) {
2549 continue;
2550 }
2551 String libFileName = entryName.substring(
2552 apkLibraryDirectory.length());
2553 if (libFileName.contains("/")
2554 || (!FileUtils.isFilenameSafe(new File(libFileName)))) {
2555 continue;
2556 }
Dianne Hackbornb1811182009-05-21 15:45:42 -07002557
2558 installedNativeCode = true;
2559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002560 String sharedLibraryFilePath = sharedLibraryDir.getPath() +
2561 File.separator + libFileName;
2562 File sharedLibraryFile = new File(sharedLibraryFilePath);
2563 if (! sharedLibraryFile.exists() ||
2564 sharedLibraryFile.length() != entry.getSize() ||
2565 sharedLibraryFile.lastModified() != entry.getTime()) {
2566 if (Config.LOGD) {
2567 Log.d(TAG, "Caching shared lib " + entry.getName());
2568 }
2569 if (mInstaller == null) {
2570 sharedLibraryDir.mkdir();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571 }
2572 cacheSharedLibLI(pkg, zipFile, entry, sharedLibraryDir,
2573 sharedLibraryFile);
2574 }
2575 }
2576 } catch (IOException e) {
Dianne Hackbornb1811182009-05-21 15:45:42 -07002577 Log.w(TAG, "Failed to cache package shared libs", e);
2578 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 }
Dianne Hackbornb1811182009-05-21 15:45:42 -07002580
2581 if (hasNativeCode && !installedNativeCode) {
2582 Log.w(TAG, "Install failed: .apk has native code but none for arch "
2583 + Build.CPU_ABI);
2584 return PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
2585 }
2586
2587 return PackageManager.INSTALL_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588 }
2589
2590 private void cacheSharedLibLI(PackageParser.Package pkg,
2591 ZipFile zipFile, ZipEntry entry,
2592 File sharedLibraryDir,
2593 File sharedLibraryFile) throws IOException {
2594 InputStream inputStream = zipFile.getInputStream(entry);
2595 try {
2596 File tempFile = File.createTempFile("tmp", "tmp", sharedLibraryDir);
2597 String tempFilePath = tempFile.getPath();
2598 // XXX package manager can't change owner, so the lib files for
2599 // now need to be left as world readable and owned by the system.
2600 if (! FileUtils.copyToFile(inputStream, tempFile) ||
2601 ! tempFile.setLastModified(entry.getTime()) ||
2602 FileUtils.setPermissions(tempFilePath,
2603 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
2604 |FileUtils.S_IROTH, -1, -1) != 0 ||
2605 ! tempFile.renameTo(sharedLibraryFile)) {
2606 // Failed to properly write file.
2607 tempFile.delete();
2608 throw new IOException("Couldn't create cached shared lib "
2609 + sharedLibraryFile + " in " + sharedLibraryDir);
2610 }
2611 } finally {
2612 inputStream.close();
2613 }
2614 }
2615
2616 void removePackageLI(PackageParser.Package pkg, boolean chatty) {
2617 if (chatty && Config.LOGD) Log.d(
2618 TAG, "Removing package " + pkg.applicationInfo.packageName );
2619
2620 synchronized (mPackages) {
2621 if (pkg.mPreferredOrder > 0) {
2622 mSettings.mPreferredPackages.remove(pkg);
2623 pkg.mPreferredOrder = 0;
2624 updatePreferredIndicesLP();
2625 }
2626
2627 clearPackagePreferredActivitiesLP(pkg.packageName);
2628
2629 mPackages.remove(pkg.applicationInfo.packageName);
2630 if (pkg.mPath != null) {
2631 mAppDirs.remove(pkg.mPath);
2632 }
2633
2634 PackageSetting ps = (PackageSetting)pkg.mExtras;
2635 if (ps != null && ps.sharedUser != null) {
2636 // XXX don't do this until the data is removed.
2637 if (false) {
2638 ps.sharedUser.packages.remove(ps);
2639 if (ps.sharedUser.packages.size() == 0) {
2640 // Remove.
2641 }
2642 }
2643 }
2644
2645 int N = pkg.providers.size();
2646 StringBuilder r = null;
2647 int i;
2648 for (i=0; i<N; i++) {
2649 PackageParser.Provider p = pkg.providers.get(i);
2650 mProvidersByComponent.remove(new ComponentName(p.info.packageName,
2651 p.info.name));
2652 if (p.info.authority == null) {
2653
2654 /* The is another ContentProvider with this authority when
2655 * this app was installed so this authority is null,
2656 * Ignore it as we don't have to unregister the provider.
2657 */
2658 continue;
2659 }
2660 String names[] = p.info.authority.split(";");
2661 for (int j = 0; j < names.length; j++) {
2662 if (mProviders.get(names[j]) == p) {
2663 mProviders.remove(names[j]);
2664 if (chatty && Config.LOGD) Log.d(
2665 TAG, "Unregistered content provider: " + names[j] +
2666 ", className = " + p.info.name +
2667 ", isSyncable = " + p.info.isSyncable);
2668 }
2669 }
2670 if (chatty) {
2671 if (r == null) {
2672 r = new StringBuilder(256);
2673 } else {
2674 r.append(' ');
2675 }
2676 r.append(p.info.name);
2677 }
2678 }
2679 if (r != null) {
2680 if (Config.LOGD) Log.d(TAG, " Providers: " + r);
2681 }
2682
2683 N = pkg.services.size();
2684 r = null;
2685 for (i=0; i<N; i++) {
2686 PackageParser.Service s = pkg.services.get(i);
2687 mServices.removeService(s);
2688 if (chatty) {
2689 if (r == null) {
2690 r = new StringBuilder(256);
2691 } else {
2692 r.append(' ');
2693 }
2694 r.append(s.info.name);
2695 }
2696 }
2697 if (r != null) {
2698 if (Config.LOGD) Log.d(TAG, " Services: " + r);
2699 }
2700
2701 N = pkg.receivers.size();
2702 r = null;
2703 for (i=0; i<N; i++) {
2704 PackageParser.Activity a = pkg.receivers.get(i);
2705 mReceivers.removeActivity(a, "receiver");
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, " Receivers: " + r);
2717 }
2718
2719 N = pkg.activities.size();
2720 r = null;
2721 for (i=0; i<N; i++) {
2722 PackageParser.Activity a = pkg.activities.get(i);
2723 mActivities.removeActivity(a, "activity");
2724 if (chatty) {
2725 if (r == null) {
2726 r = new StringBuilder(256);
2727 } else {
2728 r.append(' ');
2729 }
2730 r.append(a.info.name);
2731 }
2732 }
2733 if (r != null) {
2734 if (Config.LOGD) Log.d(TAG, " Activities: " + r);
2735 }
2736
2737 N = pkg.permissions.size();
2738 r = null;
2739 for (i=0; i<N; i++) {
2740 PackageParser.Permission p = pkg.permissions.get(i);
2741 boolean tree = false;
2742 BasePermission bp = mSettings.mPermissions.get(p.info.name);
2743 if (bp == null) {
2744 tree = true;
2745 bp = mSettings.mPermissionTrees.get(p.info.name);
2746 }
2747 if (bp != null && bp.perm == p) {
2748 if (bp.type != BasePermission.TYPE_BUILTIN) {
2749 if (tree) {
2750 mSettings.mPermissionTrees.remove(p.info.name);
2751 } else {
2752 mSettings.mPermissions.remove(p.info.name);
2753 }
2754 } else {
2755 bp.perm = null;
2756 }
2757 if (chatty) {
2758 if (r == null) {
2759 r = new StringBuilder(256);
2760 } else {
2761 r.append(' ');
2762 }
2763 r.append(p.info.name);
2764 }
2765 }
2766 }
2767 if (r != null) {
2768 if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
2769 }
2770
2771 N = pkg.instrumentation.size();
2772 r = null;
2773 for (i=0; i<N; i++) {
2774 PackageParser.Instrumentation a = pkg.instrumentation.get(i);
2775 mInstrumentation.remove(a.component);
2776 if (chatty) {
2777 if (r == null) {
2778 r = new StringBuilder(256);
2779 } else {
2780 r.append(' ');
2781 }
2782 r.append(a.info.name);
2783 }
2784 }
2785 if (r != null) {
2786 if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
2787 }
2788 }
2789 }
2790
2791 private static final boolean isPackageFilename(String name) {
2792 return name != null && name.endsWith(".apk");
2793 }
2794
2795 private void updatePermissionsLP() {
2796 // Make sure there are no dangling permission trees.
2797 Iterator<BasePermission> it = mSettings.mPermissionTrees
2798 .values().iterator();
2799 while (it.hasNext()) {
2800 BasePermission bp = it.next();
2801 if (bp.perm == null) {
2802 Log.w(TAG, "Removing dangling permission tree: " + bp.name
2803 + " from package " + bp.sourcePackage);
2804 it.remove();
2805 }
2806 }
2807
2808 // Make sure all dynamic permissions have been assigned to a package,
2809 // and make sure there are no dangling permissions.
2810 it = mSettings.mPermissions.values().iterator();
2811 while (it.hasNext()) {
2812 BasePermission bp = it.next();
2813 if (bp.type == BasePermission.TYPE_DYNAMIC) {
2814 if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
2815 + bp.name + " pkg=" + bp.sourcePackage
2816 + " info=" + bp.pendingInfo);
2817 if (bp.perm == null && bp.pendingInfo != null) {
2818 BasePermission tree = findPermissionTreeLP(bp.name);
2819 if (tree != null) {
2820 bp.perm = new PackageParser.Permission(tree.perm.owner,
2821 new PermissionInfo(bp.pendingInfo));
2822 bp.perm.info.packageName = tree.perm.info.packageName;
2823 bp.perm.info.name = bp.name;
2824 bp.uid = tree.uid;
2825 }
2826 }
2827 }
2828 if (bp.perm == null) {
2829 Log.w(TAG, "Removing dangling permission: " + bp.name
2830 + " from package " + bp.sourcePackage);
2831 it.remove();
2832 }
2833 }
2834
2835 // Now update the permissions for all packages, in particular
2836 // replace the granted permissions of the system packages.
2837 for (PackageParser.Package pkg : mPackages.values()) {
2838 grantPermissionsLP(pkg, false);
2839 }
2840 }
2841
2842 private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) {
2843 final PackageSetting ps = (PackageSetting)pkg.mExtras;
2844 if (ps == null) {
2845 return;
2846 }
2847 final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
2848 boolean addedPermission = false;
2849
2850 if (replace) {
2851 ps.permissionsFixed = false;
2852 if (gp == ps) {
2853 gp.grantedPermissions.clear();
2854 gp.gids = mGlobalGids;
2855 }
2856 }
2857
2858 if (gp.gids == null) {
2859 gp.gids = mGlobalGids;
2860 }
2861
2862 final int N = pkg.requestedPermissions.size();
2863 for (int i=0; i<N; i++) {
2864 String name = pkg.requestedPermissions.get(i);
2865 BasePermission bp = mSettings.mPermissions.get(name);
2866 PackageParser.Permission p = bp != null ? bp.perm : null;
2867 if (false) {
2868 if (gp != ps) {
2869 Log.i(TAG, "Package " + pkg.packageName + " checking " + name
2870 + ": " + p);
2871 }
2872 }
2873 if (p != null) {
2874 final String perm = p.info.name;
2875 boolean allowed;
2876 if (p.info.protectionLevel == PermissionInfo.PROTECTION_NORMAL
2877 || p.info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
2878 allowed = true;
2879 } else if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
2880 || p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
2881 allowed = (checkSignaturesLP(p.owner, pkg)
2882 == PackageManager.SIGNATURE_MATCH)
2883 || (checkSignaturesLP(mPlatformPackage, pkg)
2884 == PackageManager.SIGNATURE_MATCH);
2885 if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
2886 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
2887 // For updated system applications, the signatureOrSystem permission
2888 // is granted only if it had been defined by the original application.
2889 if ((pkg.applicationInfo.flags
2890 & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
2891 PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName);
2892 if(sysPs.grantedPermissions.contains(perm)) {
2893 allowed = true;
2894 } else {
2895 allowed = false;
2896 }
2897 } else {
2898 allowed = true;
2899 }
2900 }
2901 }
2902 } else {
2903 allowed = false;
2904 }
2905 if (false) {
2906 if (gp != ps) {
2907 Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
2908 }
2909 }
2910 if (allowed) {
2911 if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0
2912 && ps.permissionsFixed) {
2913 // If this is an existing, non-system package, then
2914 // we can't add any new permissions to it.
2915 if (!gp.loadedPermissions.contains(perm)) {
2916 allowed = false;
Dianne Hackborna96cbb42009-05-13 15:06:13 -07002917 // Except... if this is a permission that was added
2918 // to the platform (note: need to only do this when
2919 // updating the platform).
2920 final int NP = PackageParser.NEW_PERMISSIONS.length;
2921 for (int ip=0; ip<NP; ip++) {
2922 final PackageParser.NewPermissionInfo npi
2923 = PackageParser.NEW_PERMISSIONS[ip];
2924 if (npi.name.equals(perm)
2925 && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
2926 allowed = true;
San Mehat5a3a77d2009-06-01 09:25:28 -07002927 Log.i(TAG, "Auto-granting WRITE_EXTERNAL_STORAGE to old pkg "
Dianne Hackborna96cbb42009-05-13 15:06:13 -07002928 + pkg.packageName);
2929 break;
2930 }
2931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002932 }
2933 }
2934 if (allowed) {
2935 if (!gp.grantedPermissions.contains(perm)) {
2936 addedPermission = true;
2937 gp.grantedPermissions.add(perm);
2938 gp.gids = appendInts(gp.gids, bp.gids);
2939 }
2940 } else {
2941 Log.w(TAG, "Not granting permission " + perm
2942 + " to package " + pkg.packageName
2943 + " because it was previously installed without");
2944 }
2945 } else {
2946 Log.w(TAG, "Not granting permission " + perm
2947 + " to package " + pkg.packageName
2948 + " (protectionLevel=" + p.info.protectionLevel
2949 + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
2950 + ")");
2951 }
2952 } else {
2953 Log.w(TAG, "Unknown permission " + name
2954 + " in package " + pkg.packageName);
2955 }
2956 }
2957
2958 if ((addedPermission || replace) && !ps.permissionsFixed &&
2959 (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
2960 // This is the first that we have heard about this package, so the
2961 // permissions we have now selected are fixed until explicitly
2962 // changed.
2963 ps.permissionsFixed = true;
2964 gp.loadedPermissions = new HashSet<String>(gp.grantedPermissions);
2965 }
2966 }
2967
2968 private final class ActivityIntentResolver
2969 extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
Mihai Preda074edef2009-05-18 17:13:31 +02002970 public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002971 mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
Mihai Preda074edef2009-05-18 17:13:31 +02002972 return super.queryIntent(intent, resolvedType, defaultOnly);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002973 }
2974
Mihai Preda074edef2009-05-18 17:13:31 +02002975 public List queryIntent(Intent intent, String resolvedType, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976 mFlags = flags;
Mihai Preda074edef2009-05-18 17:13:31 +02002977 return super.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002978 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
2979 }
2980
Mihai Predaeae850c2009-05-13 10:13:48 +02002981 public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
2982 ArrayList<PackageParser.Activity> packageActivities) {
2983 if (packageActivities == null) {
2984 return null;
2985 }
2986 mFlags = flags;
2987 final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
2988 int N = packageActivities.size();
2989 ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut =
2990 new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N);
Mihai Predac3320db2009-05-18 20:15:32 +02002991
2992 ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
Mihai Predaeae850c2009-05-13 10:13:48 +02002993 for (int i = 0; i < N; ++i) {
Mihai Predac3320db2009-05-18 20:15:32 +02002994 intentFilters = packageActivities.get(i).intents;
2995 if (intentFilters != null && intentFilters.size() > 0) {
2996 listCut.add(intentFilters);
2997 }
Mihai Predaeae850c2009-05-13 10:13:48 +02002998 }
2999 return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
3000 }
3001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003002 public final void addActivity(PackageParser.Activity a, String type) {
3003 mActivities.put(a.component, a);
3004 if (SHOW_INFO || Config.LOGV) Log.v(
3005 TAG, " " + type + " " +
3006 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
3007 if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
3008 int NI = a.intents.size();
Mihai Predaeae850c2009-05-13 10:13:48 +02003009 for (int j=0; j<NI; j++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
3011 if (SHOW_INFO || Config.LOGV) {
3012 Log.v(TAG, " IntentFilter:");
3013 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3014 }
3015 if (!intent.debugCheck()) {
3016 Log.w(TAG, "==> For Activity " + a.info.name);
3017 }
3018 addFilter(intent);
3019 }
3020 }
3021
3022 public final void removeActivity(PackageParser.Activity a, String type) {
3023 mActivities.remove(a.component);
3024 if (SHOW_INFO || Config.LOGV) Log.v(
3025 TAG, " " + type + " " +
3026 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
3027 if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
3028 int NI = a.intents.size();
Mihai Predaeae850c2009-05-13 10:13:48 +02003029 for (int j=0; j<NI; j++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003030 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
3031 if (SHOW_INFO || Config.LOGV) {
3032 Log.v(TAG, " IntentFilter:");
3033 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3034 }
3035 removeFilter(intent);
3036 }
3037 }
3038
3039 @Override
3040 protected boolean allowFilterResult(
3041 PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {
3042 ActivityInfo filterAi = filter.activity.info;
3043 for (int i=dest.size()-1; i>=0; i--) {
3044 ActivityInfo destAi = dest.get(i).activityInfo;
3045 if (destAi.name == filterAi.name
3046 && destAi.packageName == filterAi.packageName) {
3047 return false;
3048 }
3049 }
3050 return true;
3051 }
3052
3053 @Override
3054 protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
3055 int match) {
3056 if (!mSettings.isEnabledLP(info.activity.info, mFlags)) {
3057 return null;
3058 }
3059 final PackageParser.Activity activity = info.activity;
3060 if (mSafeMode && (activity.info.applicationInfo.flags
3061 &ApplicationInfo.FLAG_SYSTEM) == 0) {
3062 return null;
3063 }
3064 final ResolveInfo res = new ResolveInfo();
3065 res.activityInfo = PackageParser.generateActivityInfo(activity,
3066 mFlags);
3067 if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
3068 res.filter = info;
3069 }
3070 res.priority = info.getPriority();
3071 res.preferredOrder = activity.owner.mPreferredOrder;
3072 //System.out.println("Result: " + res.activityInfo.className +
3073 // " = " + res.priority);
3074 res.match = match;
3075 res.isDefault = info.hasDefault;
3076 res.labelRes = info.labelRes;
3077 res.nonLocalizedLabel = info.nonLocalizedLabel;
3078 res.icon = info.icon;
3079 return res;
3080 }
3081
3082 @Override
3083 protected void sortResults(List<ResolveInfo> results) {
3084 Collections.sort(results, mResolvePrioritySorter);
3085 }
3086
3087 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003088 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003089 PackageParser.ActivityIntentInfo filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003090 out.print(prefix); out.print(
3091 Integer.toHexString(System.identityHashCode(filter.activity)));
3092 out.print(' ');
3093 out.println(filter.activity.componentShortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003094 }
3095
3096// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
3097// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
3098// final List<ResolveInfo> retList = Lists.newArrayList();
3099// while (i.hasNext()) {
3100// final ResolveInfo resolveInfo = i.next();
3101// if (isEnabledLP(resolveInfo.activityInfo)) {
3102// retList.add(resolveInfo);
3103// }
3104// }
3105// return retList;
3106// }
3107
3108 // Keys are String (activity class name), values are Activity.
3109 private final HashMap<ComponentName, PackageParser.Activity> mActivities
3110 = new HashMap<ComponentName, PackageParser.Activity>();
3111 private int mFlags;
3112 }
3113
3114 private final class ServiceIntentResolver
3115 extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
Mihai Preda074edef2009-05-18 17:13:31 +02003116 public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117 mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
Mihai Preda074edef2009-05-18 17:13:31 +02003118 return super.queryIntent(intent, resolvedType, defaultOnly);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003119 }
3120
Mihai Preda074edef2009-05-18 17:13:31 +02003121 public List queryIntent(Intent intent, String resolvedType, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003122 mFlags = flags;
Mihai Preda074edef2009-05-18 17:13:31 +02003123 return super.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003124 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
3125 }
3126
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07003127 public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
3128 ArrayList<PackageParser.Service> packageServices) {
3129 if (packageServices == null) {
3130 return null;
3131 }
3132 mFlags = flags;
3133 final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
3134 int N = packageServices.size();
3135 ArrayList<ArrayList<PackageParser.ServiceIntentInfo>> listCut =
3136 new ArrayList<ArrayList<PackageParser.ServiceIntentInfo>>(N);
3137
3138 ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
3139 for (int i = 0; i < N; ++i) {
3140 intentFilters = packageServices.get(i).intents;
3141 if (intentFilters != null && intentFilters.size() > 0) {
3142 listCut.add(intentFilters);
3143 }
3144 }
3145 return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
3146 }
3147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 public final void addService(PackageParser.Service s) {
3149 mServices.put(s.component, s);
3150 if (SHOW_INFO || Config.LOGV) Log.v(
3151 TAG, " " + (s.info.nonLocalizedLabel != null
3152 ? s.info.nonLocalizedLabel : s.info.name) + ":");
3153 if (SHOW_INFO || Config.LOGV) Log.v(
3154 TAG, " Class=" + s.info.name);
3155 int NI = s.intents.size();
3156 int j;
3157 for (j=0; j<NI; j++) {
3158 PackageParser.ServiceIntentInfo intent = s.intents.get(j);
3159 if (SHOW_INFO || Config.LOGV) {
3160 Log.v(TAG, " IntentFilter:");
3161 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3162 }
3163 if (!intent.debugCheck()) {
3164 Log.w(TAG, "==> For Service " + s.info.name);
3165 }
3166 addFilter(intent);
3167 }
3168 }
3169
3170 public final void removeService(PackageParser.Service s) {
3171 mServices.remove(s.component);
3172 if (SHOW_INFO || Config.LOGV) Log.v(
3173 TAG, " " + (s.info.nonLocalizedLabel != null
3174 ? s.info.nonLocalizedLabel : s.info.name) + ":");
3175 if (SHOW_INFO || Config.LOGV) Log.v(
3176 TAG, " Class=" + s.info.name);
3177 int NI = s.intents.size();
3178 int j;
3179 for (j=0; j<NI; j++) {
3180 PackageParser.ServiceIntentInfo intent = s.intents.get(j);
3181 if (SHOW_INFO || Config.LOGV) {
3182 Log.v(TAG, " IntentFilter:");
3183 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3184 }
3185 removeFilter(intent);
3186 }
3187 }
3188
3189 @Override
3190 protected boolean allowFilterResult(
3191 PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) {
3192 ServiceInfo filterSi = filter.service.info;
3193 for (int i=dest.size()-1; i>=0; i--) {
3194 ServiceInfo destAi = dest.get(i).serviceInfo;
3195 if (destAi.name == filterSi.name
3196 && destAi.packageName == filterSi.packageName) {
3197 return false;
3198 }
3199 }
3200 return true;
3201 }
3202
3203 @Override
3204 protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
3205 int match) {
3206 final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
3207 if (!mSettings.isEnabledLP(info.service.info, mFlags)) {
3208 return null;
3209 }
3210 final PackageParser.Service service = info.service;
3211 if (mSafeMode && (service.info.applicationInfo.flags
3212 &ApplicationInfo.FLAG_SYSTEM) == 0) {
3213 return null;
3214 }
3215 final ResolveInfo res = new ResolveInfo();
3216 res.serviceInfo = PackageParser.generateServiceInfo(service,
3217 mFlags);
3218 if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
3219 res.filter = filter;
3220 }
3221 res.priority = info.getPriority();
3222 res.preferredOrder = service.owner.mPreferredOrder;
3223 //System.out.println("Result: " + res.activityInfo.className +
3224 // " = " + res.priority);
3225 res.match = match;
3226 res.isDefault = info.hasDefault;
3227 res.labelRes = info.labelRes;
3228 res.nonLocalizedLabel = info.nonLocalizedLabel;
3229 res.icon = info.icon;
3230 return res;
3231 }
3232
3233 @Override
3234 protected void sortResults(List<ResolveInfo> results) {
3235 Collections.sort(results, mResolvePrioritySorter);
3236 }
3237
3238 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003239 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 PackageParser.ServiceIntentInfo filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003241 out.print(prefix); out.print(
3242 Integer.toHexString(System.identityHashCode(filter.service)));
3243 out.print(' ');
3244 out.println(filter.service.componentShortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003245 }
3246
3247// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
3248// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
3249// final List<ResolveInfo> retList = Lists.newArrayList();
3250// while (i.hasNext()) {
3251// final ResolveInfo resolveInfo = (ResolveInfo) i;
3252// if (isEnabledLP(resolveInfo.serviceInfo)) {
3253// retList.add(resolveInfo);
3254// }
3255// }
3256// return retList;
3257// }
3258
3259 // Keys are String (activity class name), values are Activity.
3260 private final HashMap<ComponentName, PackageParser.Service> mServices
3261 = new HashMap<ComponentName, PackageParser.Service>();
3262 private int mFlags;
3263 };
3264
3265 private static final Comparator<ResolveInfo> mResolvePrioritySorter =
3266 new Comparator<ResolveInfo>() {
3267 public int compare(ResolveInfo r1, ResolveInfo r2) {
3268 int v1 = r1.priority;
3269 int v2 = r2.priority;
3270 //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
3271 if (v1 != v2) {
3272 return (v1 > v2) ? -1 : 1;
3273 }
3274 v1 = r1.preferredOrder;
3275 v2 = r2.preferredOrder;
3276 if (v1 != v2) {
3277 return (v1 > v2) ? -1 : 1;
3278 }
3279 if (r1.isDefault != r2.isDefault) {
3280 return r1.isDefault ? -1 : 1;
3281 }
3282 v1 = r1.match;
3283 v2 = r2.match;
3284 //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
3285 return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
3286 }
3287 };
3288
3289 private static final Comparator<ProviderInfo> mProviderInitOrderSorter =
3290 new Comparator<ProviderInfo>() {
3291 public int compare(ProviderInfo p1, ProviderInfo p2) {
3292 final int v1 = p1.initOrder;
3293 final int v2 = p2.initOrder;
3294 return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
3295 }
3296 };
3297
3298 private static final void sendPackageBroadcast(String action, String pkg, Bundle extras) {
3299 IActivityManager am = ActivityManagerNative.getDefault();
3300 if (am != null) {
3301 try {
3302 final Intent intent = new Intent(action,
3303 pkg != null ? Uri.fromParts("package", pkg, null) : null);
3304 if (extras != null) {
3305 intent.putExtras(extras);
3306 }
3307 am.broadcastIntent(
3308 null, intent,
3309 null, null, 0, null, null, null, false, false);
3310 } catch (RemoteException ex) {
3311 }
3312 }
3313 }
3314
3315 private final class AppDirObserver extends FileObserver {
3316 public AppDirObserver(String path, int mask, boolean isrom) {
3317 super(path, mask);
3318 mRootDir = path;
3319 mIsRom = isrom;
3320 }
3321
3322 public void onEvent(int event, String path) {
3323 String removedPackage = null;
3324 int removedUid = -1;
3325 String addedPackage = null;
3326 int addedUid = -1;
3327
3328 synchronized (mInstallLock) {
3329 String fullPathStr = null;
3330 File fullPath = null;
3331 if (path != null) {
3332 fullPath = new File(mRootDir, path);
3333 fullPathStr = fullPath.getPath();
3334 }
3335
3336 if (Config.LOGV) Log.v(
3337 TAG, "File " + fullPathStr + " changed: "
3338 + Integer.toHexString(event));
3339
3340 if (!isPackageFilename(path)) {
3341 if (Config.LOGV) Log.v(
3342 TAG, "Ignoring change of non-package file: " + fullPathStr);
3343 return;
3344 }
3345
3346 if ((event&REMOVE_EVENTS) != 0) {
3347 synchronized (mInstallLock) {
3348 PackageParser.Package p = mAppDirs.get(fullPathStr);
3349 if (p != null) {
3350 removePackageLI(p, true);
3351 removedPackage = p.applicationInfo.packageName;
3352 removedUid = p.applicationInfo.uid;
3353 }
3354 }
3355 }
3356
3357 if ((event&ADD_EVENTS) != 0) {
3358 PackageParser.Package p = mAppDirs.get(fullPathStr);
3359 if (p == null) {
3360 p = scanPackageLI(fullPath, fullPath, fullPath,
3361 (mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) |
3362 PackageParser.PARSE_CHATTY |
3363 PackageParser.PARSE_MUST_BE_APK,
3364 SCAN_MONITOR);
3365 if (p != null) {
3366 synchronized (mPackages) {
3367 grantPermissionsLP(p, false);
3368 }
3369 addedPackage = p.applicationInfo.packageName;
3370 addedUid = p.applicationInfo.uid;
3371 }
3372 }
3373 }
3374
3375 synchronized (mPackages) {
3376 mSettings.writeLP();
3377 }
3378 }
3379
3380 if (removedPackage != null) {
3381 Bundle extras = new Bundle(1);
3382 extras.putInt(Intent.EXTRA_UID, removedUid);
3383 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
3384 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
3385 }
3386 if (addedPackage != null) {
3387 Bundle extras = new Bundle(1);
3388 extras.putInt(Intent.EXTRA_UID, addedUid);
3389 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras);
3390 }
3391 }
3392
3393 private final String mRootDir;
3394 private final boolean mIsRom;
3395 }
Jacek Surazskic64322c2009-04-28 15:26:38 +02003396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003397 /* Called when a downloaded package installation has been confirmed by the user */
3398 public void installPackage(
3399 final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
Jacek Surazskic64322c2009-04-28 15:26:38 +02003400 installPackage(packageURI, observer, flags, null);
3401 }
3402
3403 /* Called when a downloaded package installation has been confirmed by the user */
3404 public void installPackage(
3405 final Uri packageURI, final IPackageInstallObserver observer, final int flags,
3406 final String installerPackageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 mContext.enforceCallingOrSelfPermission(
3408 android.Manifest.permission.INSTALL_PACKAGES, null);
Jacek Surazskic64322c2009-04-28 15:26:38 +02003409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003410 // Queue up an async operation since the package installation may take a little while.
3411 mHandler.post(new Runnable() {
3412 public void run() {
3413 mHandler.removeCallbacks(this);
3414 PackageInstalledInfo res;
3415 synchronized (mInstallLock) {
Jacek Surazskic64322c2009-04-28 15:26:38 +02003416 res = installPackageLI(packageURI, flags, true, installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003417 }
3418 if (observer != null) {
3419 try {
3420 observer.packageInstalled(res.name, res.returnCode);
3421 } catch (RemoteException e) {
3422 Log.i(TAG, "Observer no longer exists.");
3423 }
3424 }
3425 // There appears to be a subtle deadlock condition if the sendPackageBroadcast
3426 // call appears in the synchronized block above.
3427 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
3428 res.removedInfo.sendBroadcast(false, true);
3429 Bundle extras = new Bundle(1);
3430 extras.putInt(Intent.EXTRA_UID, res.uid);
Dianne Hackbornf63220f2009-03-24 18:38:43 -07003431 final boolean update = res.removedInfo.removedPackage != null;
3432 if (update) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 extras.putBoolean(Intent.EXTRA_REPLACING, true);
3434 }
3435 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
3436 res.pkg.applicationInfo.packageName,
3437 extras);
Dianne Hackbornf63220f2009-03-24 18:38:43 -07003438 if (update) {
3439 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
3440 res.pkg.applicationInfo.packageName,
3441 extras);
3442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003443 }
3444 Runtime.getRuntime().gc();
3445 }
3446 });
3447 }
3448
3449 class PackageInstalledInfo {
3450 String name;
3451 int uid;
3452 PackageParser.Package pkg;
3453 int returnCode;
3454 PackageRemovedInfo removedInfo;
3455 }
3456
3457 /*
3458 * Install a non-existing package.
3459 */
3460 private void installNewPackageLI(String pkgName,
3461 File tmpPackageFile,
3462 String destFilePath, File destPackageFile, File destResourceFile,
The Android Open Source Project10592532009-03-18 17:39:46 -07003463 PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003464 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003465 // Remember this for later, in case we need to rollback this install
3466 boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists();
3467 res.name = pkgName;
3468 synchronized(mPackages) {
3469 if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) {
3470 // Don't allow installation over an existing package with the same name.
3471 Log.w(TAG, "Attempt to re-install " + pkgName
3472 + " without first uninstalling.");
3473 res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
3474 return;
3475 }
3476 }
3477 if (destPackageFile.exists()) {
3478 // It's safe to do this because we know (from the above check) that the file
3479 // isn't currently used for an installed package.
3480 destPackageFile.delete();
3481 }
3482 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
3483 PackageParser.Package newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
3484 destResourceFile, pkg, 0,
3485 SCAN_MONITOR | SCAN_FORCE_DEX
3486 | SCAN_UPDATE_SIGNATURE
The Android Open Source Project10592532009-03-18 17:39:46 -07003487 | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
3488 | (newInstall ? SCAN_NEW_INSTALL : 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 if (newPackage == null) {
3490 Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
3491 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
3492 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
3493 }
3494 } else {
3495 updateSettingsLI(pkgName, tmpPackageFile,
3496 destFilePath, destPackageFile,
3497 destResourceFile, pkg,
3498 newPackage,
3499 true,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003500 forwardLocked,
3501 installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003502 res);
3503 // delete the partially installed application. the data directory will have to be
3504 // restored if it was already existing
3505 if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
3506 // remove package from internal structures. Note that we want deletePackageX to
3507 // delete the package data and cache directories that it created in
3508 // scanPackageLocked, unless those directories existed before we even tried to
3509 // install.
3510 deletePackageLI(
3511 pkgName, true,
3512 dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
3513 res.removedInfo);
3514 }
3515 }
3516 }
3517
3518 private void replacePackageLI(String pkgName,
3519 File tmpPackageFile,
3520 String destFilePath, File destPackageFile, File destResourceFile,
The Android Open Source Project10592532009-03-18 17:39:46 -07003521 PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003522 String installerPackageName, PackageInstalledInfo res) {
3523
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003524 PackageParser.Package oldPackage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 // First find the old package info and check signatures
3526 synchronized(mPackages) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003527 oldPackage = mPackages.get(pkgName);
3528 if(checkSignaturesLP(pkg, oldPackage) != PackageManager.SIGNATURE_MATCH) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003529 res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
3530 return;
3531 }
3532 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003533 boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534 if(sysPkg) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003535 replaceSystemPackageLI(oldPackage,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003536 tmpPackageFile, destFilePath,
The Android Open Source Project10592532009-03-18 17:39:46 -07003537 destPackageFile, destResourceFile, pkg, forwardLocked,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003538 newInstall, installerPackageName, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 } else {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07003540 replaceNonSystemPackageLI(oldPackage, tmpPackageFile, destFilePath,
The Android Open Source Project10592532009-03-18 17:39:46 -07003541 destPackageFile, destResourceFile, pkg, forwardLocked,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003542 newInstall, installerPackageName, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003543 }
3544 }
3545
3546 private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
3547 File tmpPackageFile,
3548 String destFilePath, File destPackageFile, File destResourceFile,
The Android Open Source Project10592532009-03-18 17:39:46 -07003549 PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003550 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003551 PackageParser.Package newPackage = null;
3552 String pkgName = deletedPackage.packageName;
3553 boolean deletedPkg = true;
3554 boolean updatedSettings = false;
Jacek Surazskic64322c2009-04-28 15:26:38 +02003555
3556 String oldInstallerPackageName = null;
3557 synchronized (mPackages) {
3558 oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
3559 }
3560
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003561 int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003562 // First delete the existing package while retaining the data directory
3563 if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
3564 res.removedInfo)) {
3565 // If the existing package was'nt successfully deleted
3566 res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
3567 deletedPkg = false;
3568 } else {
3569 // Successfully deleted the old package. Now proceed with re-installation
3570 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
3571 newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
3572 destResourceFile, pkg, parseFlags,
3573 SCAN_MONITOR | SCAN_FORCE_DEX
3574 | SCAN_UPDATE_SIGNATURE
The Android Open Source Project10592532009-03-18 17:39:46 -07003575 | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
3576 | (newInstall ? SCAN_NEW_INSTALL : 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577 if (newPackage == null) {
3578 Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
3579 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
3580 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
3581 }
3582 } else {
3583 updateSettingsLI(pkgName, tmpPackageFile,
3584 destFilePath, destPackageFile,
3585 destResourceFile, pkg,
3586 newPackage,
3587 true,
3588 forwardLocked,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003589 installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003590 res);
3591 updatedSettings = true;
3592 }
3593 }
3594
3595 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
3596 // If we deleted an exisiting package, the old source and resource files that we
3597 // were keeping around in case we needed them (see below) can now be deleted
3598 final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo;
3599 final ApplicationInfo installedPackageAppInfo =
3600 newPackage.applicationInfo;
3601 if (!deletedPackageAppInfo.sourceDir
3602 .equals(installedPackageAppInfo.sourceDir)) {
3603 new File(deletedPackageAppInfo.sourceDir).delete();
3604 }
3605 if (!deletedPackageAppInfo.publicSourceDir
3606 .equals(installedPackageAppInfo.publicSourceDir)) {
3607 new File(deletedPackageAppInfo.publicSourceDir).delete();
3608 }
3609 //update signature on the new package setting
3610 //this should always succeed, since we checked the
3611 //signature earlier.
3612 synchronized(mPackages) {
3613 verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg,
3614 parseFlags, true);
3615 }
3616 } else {
3617 // remove package from internal structures. Note that we want deletePackageX to
3618 // delete the package data and cache directories that it created in
3619 // scanPackageLocked, unless those directories existed before we even tried to
3620 // install.
3621 if(updatedSettings) {
3622 deletePackageLI(
3623 pkgName, true,
3624 PackageManager.DONT_DELETE_DATA,
3625 res.removedInfo);
3626 }
3627 // Since we failed to install the new package we need to restore the old
3628 // package that we deleted.
3629 if(deletedPkg) {
3630 installPackageLI(
3631 Uri.fromFile(new File(deletedPackage.mPath)),
3632 isForwardLocked(deletedPackage)
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003633 ? PackageManager.INSTALL_FORWARD_LOCK
Jacek Surazskic64322c2009-04-28 15:26:38 +02003634 : 0, false, oldInstallerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003635 }
3636 }
3637 }
3638
3639 private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
3640 File tmpPackageFile,
3641 String destFilePath, File destPackageFile, File destResourceFile,
The Android Open Source Project10592532009-03-18 17:39:46 -07003642 PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003643 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003644 PackageParser.Package newPackage = null;
3645 boolean updatedSettings = false;
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003646 int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING |
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003647 PackageParser.PARSE_IS_SYSTEM;
3648 String packageName = deletedPackage.packageName;
3649 res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
3650 if (packageName == null) {
3651 Log.w(TAG, "Attempt to delete null packageName.");
3652 return;
3653 }
3654 PackageParser.Package oldPkg;
3655 PackageSetting oldPkgSetting;
3656 synchronized (mPackages) {
3657 oldPkg = mPackages.get(packageName);
3658 oldPkgSetting = mSettings.mPackages.get(packageName);
3659 if((oldPkg == null) || (oldPkg.applicationInfo == null) ||
3660 (oldPkgSetting == null)) {
3661 Log.w(TAG, "Could'nt find package:"+packageName+" information");
3662 return;
3663 }
3664 }
3665 res.removedInfo.uid = oldPkg.applicationInfo.uid;
3666 res.removedInfo.removedPackage = packageName;
3667 // Remove existing system package
3668 removePackageLI(oldPkg, true);
3669 synchronized (mPackages) {
3670 res.removedInfo.removedUid = mSettings.disableSystemPackageLP(packageName);
3671 }
3672
3673 // Successfully disabled the old package. Now proceed with re-installation
3674 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
3675 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
3676 newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
3677 destResourceFile, pkg, parseFlags,
3678 SCAN_MONITOR | SCAN_FORCE_DEX
3679 | SCAN_UPDATE_SIGNATURE
The Android Open Source Project10592532009-03-18 17:39:46 -07003680 | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
3681 | (newInstall ? SCAN_NEW_INSTALL : 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682 if (newPackage == null) {
3683 Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
3684 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
3685 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
3686 }
3687 } else {
3688 updateSettingsLI(packageName, tmpPackageFile,
3689 destFilePath, destPackageFile,
3690 destResourceFile, pkg,
3691 newPackage,
3692 true,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003693 forwardLocked,
3694 installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 res);
3696 updatedSettings = true;
3697 }
3698
3699 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
3700 //update signature on the new package setting
3701 //this should always succeed, since we checked the
3702 //signature earlier.
3703 synchronized(mPackages) {
3704 verifySignaturesLP(mSettings.mPackages.get(packageName), pkg,
3705 parseFlags, true);
3706 }
3707 } else {
3708 // Re installation failed. Restore old information
3709 // Remove new pkg information
Dianne Hackborna96cbb42009-05-13 15:06:13 -07003710 if (newPackage != null) {
3711 removePackageLI(newPackage, true);
3712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713 // Add back the old system package
3714 scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath,
3715 oldPkgSetting.resourcePath,
3716 oldPkg, parseFlags,
3717 SCAN_MONITOR
The Android Open Source Project10592532009-03-18 17:39:46 -07003718 | SCAN_UPDATE_SIGNATURE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719 // Restore the old system information in Settings
3720 synchronized(mPackages) {
3721 if(updatedSettings) {
3722 mSettings.enableSystemPackageLP(packageName);
Jacek Surazskic64322c2009-04-28 15:26:38 +02003723 mSettings.setInstallerPackageName(packageName,
3724 oldPkgSetting.installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003725 }
3726 mSettings.writeLP();
3727 }
3728 }
3729 }
3730
3731 private void updateSettingsLI(String pkgName, File tmpPackageFile,
3732 String destFilePath, File destPackageFile,
3733 File destResourceFile,
3734 PackageParser.Package pkg,
3735 PackageParser.Package newPackage,
3736 boolean replacingExistingPackage,
3737 boolean forwardLocked,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003738 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739 synchronized (mPackages) {
3740 //write settings. the installStatus will be incomplete at this stage.
3741 //note that the new package setting would have already been
3742 //added to mPackages. It hasn't been persisted yet.
3743 mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE);
3744 mSettings.writeLP();
3745 }
3746
3747 int retCode = 0;
3748 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
3749 retCode = mInstaller.movedex(tmpPackageFile.toString(),
3750 destPackageFile.toString());
3751 if (retCode != 0) {
3752 Log.e(TAG, "Couldn't rename dex file: " + destPackageFile);
3753 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3754 return;
3755 }
3756 }
3757 // XXX There are probably some big issues here: upon doing
3758 // the rename, we have reached the point of no return (the
3759 // original .apk is gone!), so we can't fail. Yet... we can.
3760 if (!tmpPackageFile.renameTo(destPackageFile)) {
3761 Log.e(TAG, "Couldn't move package file to: " + destPackageFile);
3762 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3763 } else {
3764 res.returnCode = setPermissionsLI(pkgName, newPackage, destFilePath,
3765 destResourceFile,
3766 forwardLocked);
3767 if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
3768 return;
3769 } else {
3770 Log.d(TAG, "New package installed in " + destPackageFile);
3771 }
3772 }
3773 if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
3774 if (mInstaller != null) {
3775 mInstaller.rmdex(tmpPackageFile.getPath());
3776 }
3777 }
3778
3779 synchronized (mPackages) {
3780 grantPermissionsLP(newPackage, true);
3781 res.name = pkgName;
3782 res.uid = newPackage.applicationInfo.uid;
3783 res.pkg = newPackage;
3784 mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
Jacek Surazskic64322c2009-04-28 15:26:38 +02003785 mSettings.setInstallerPackageName(pkgName, installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003786 res.returnCode = PackageManager.INSTALL_SUCCEEDED;
3787 //to update install status
3788 mSettings.writeLP();
3789 }
3790 }
3791
The Android Open Source Project10592532009-03-18 17:39:46 -07003792 private PackageInstalledInfo installPackageLI(Uri pPackageURI,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003793 int pFlags, boolean newInstall, String installerPackageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 File tmpPackageFile = null;
3795 String pkgName = null;
3796 boolean forwardLocked = false;
3797 boolean replacingExistingPackage = false;
3798 // Result object to be returned
3799 PackageInstalledInfo res = new PackageInstalledInfo();
3800 res.returnCode = PackageManager.INSTALL_SUCCEEDED;
3801 res.uid = -1;
3802 res.pkg = null;
3803 res.removedInfo = new PackageRemovedInfo();
3804
3805 main_flow: try {
3806 tmpPackageFile = createTempPackageFile();
3807 if (tmpPackageFile == null) {
3808 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3809 break main_flow;
3810 }
3811 tmpPackageFile.deleteOnExit(); // paranoia
3812 if (pPackageURI.getScheme().equals("file")) {
3813 final File srcPackageFile = new File(pPackageURI.getPath());
3814 // We copy the source package file to a temp file and then rename it to the
3815 // destination file in order to eliminate a window where the package directory
3816 // scanner notices the new package file but it's not completely copied yet.
3817 if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
3818 Log.e(TAG, "Couldn't copy package file to temp file.");
3819 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3820 break main_flow;
3821 }
3822 } else if (pPackageURI.getScheme().equals("content")) {
3823 ParcelFileDescriptor fd;
3824 try {
3825 fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
3826 } catch (FileNotFoundException e) {
3827 Log.e(TAG, "Couldn't open file descriptor from download service.");
3828 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3829 break main_flow;
3830 }
3831 if (fd == null) {
3832 Log.e(TAG, "Couldn't open file descriptor from download service (null).");
3833 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3834 break main_flow;
3835 }
3836 if (Config.LOGV) {
3837 Log.v(TAG, "Opened file descriptor from download service.");
3838 }
3839 ParcelFileDescriptor.AutoCloseInputStream
3840 dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd);
3841 // We copy the source package file to a temp file and then rename it to the
3842 // destination file in order to eliminate a window where the package directory
3843 // scanner notices the new package file but it's not completely copied yet.
3844 if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) {
3845 Log.e(TAG, "Couldn't copy package stream to temp file.");
3846 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3847 break main_flow;
3848 }
3849 } else {
3850 Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
3851 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI;
3852 break main_flow;
3853 }
3854 pkgName = PackageParser.parsePackageName(
3855 tmpPackageFile.getAbsolutePath(), 0);
3856 if (pkgName == null) {
3857 Log.e(TAG, "Couldn't find a package name in : " + tmpPackageFile);
3858 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
3859 break main_flow;
3860 }
3861 res.name = pkgName;
3862 //initialize some variables before installing pkg
3863 final String pkgFileName = pkgName + ".apk";
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003864 final File destDir = ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003865 ? mDrmAppPrivateInstallDir
3866 : mAppInstallDir;
3867 final File destPackageFile = new File(destDir, pkgFileName);
3868 final String destFilePath = destPackageFile.getAbsolutePath();
3869 File destResourceFile;
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003870 if ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003871 final String publicZipFileName = pkgName + ".zip";
3872 destResourceFile = new File(mAppInstallDir, publicZipFileName);
3873 forwardLocked = true;
3874 } else {
3875 destResourceFile = destPackageFile;
3876 }
3877 // Retrieve PackageSettings and parse package
3878 int parseFlags = PackageParser.PARSE_CHATTY;
3879 parseFlags |= mDefParseFlags;
3880 PackageParser pp = new PackageParser(tmpPackageFile.getPath());
3881 pp.setSeparateProcesses(mSeparateProcesses);
Dianne Hackborn851a5412009-05-08 12:06:44 -07003882 pp.setSdkVersion(mSdkVersion, mSdkCodename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003883 final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
3884 destPackageFile.getAbsolutePath(), mMetrics, parseFlags);
3885 if (pkg == null) {
3886 res.returnCode = pp.getParseError();
3887 break main_flow;
3888 }
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003889 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
3890 if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
3891 res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
3892 break main_flow;
3893 }
3894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003895 if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
3896 res.returnCode = pp.getParseError();
3897 break main_flow;
3898 }
3899
3900 synchronized (mPackages) {
3901 //check if installing already existing package
Dianne Hackbornade3eca2009-05-11 18:54:45 -07003902 if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 && mPackages.containsKey(pkgName)) {
3904 replacingExistingPackage = true;
3905 }
3906 }
3907
3908 if(replacingExistingPackage) {
3909 replacePackageLI(pkgName,
3910 tmpPackageFile,
3911 destFilePath, destPackageFile, destResourceFile,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003912 pkg, forwardLocked, newInstall, installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003913 res);
3914 } else {
3915 installNewPackageLI(pkgName,
3916 tmpPackageFile,
3917 destFilePath, destPackageFile, destResourceFile,
Jacek Surazskic64322c2009-04-28 15:26:38 +02003918 pkg, forwardLocked, newInstall, installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003919 res);
3920 }
3921 } finally {
3922 if (tmpPackageFile != null && tmpPackageFile.exists()) {
3923 tmpPackageFile.delete();
3924 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003925 }
The Android Open Source Project10592532009-03-18 17:39:46 -07003926 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003927 }
3928
3929 private int setPermissionsLI(String pkgName,
3930 PackageParser.Package newPackage,
3931 String destFilePath,
3932 File destResourceFile,
3933 boolean forwardLocked) {
3934 int retCode;
3935 if (forwardLocked) {
3936 try {
3937 extractPublicFiles(newPackage, destResourceFile);
3938 } catch (IOException e) {
3939 Log.e(TAG, "Couldn't create a new zip file for the public parts of a" +
3940 " forward-locked app.");
3941 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3942 } finally {
3943 //TODO clean up the extracted public files
3944 }
3945 if (mInstaller != null) {
3946 retCode = mInstaller.setForwardLockPerm(pkgName,
3947 newPackage.applicationInfo.uid);
3948 } else {
3949 final int filePermissions =
3950 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
3951 retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1,
3952 newPackage.applicationInfo.uid);
3953 }
3954 } else {
3955 final int filePermissions =
3956 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
3957 |FileUtils.S_IROTH;
3958 retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1);
3959 }
3960 if (retCode != 0) {
3961 Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath
3962 + ". The return code was: " + retCode);
3963 }
3964 return PackageManager.INSTALL_SUCCEEDED;
3965 }
3966
3967 private boolean isForwardLocked(PackageParser.Package deletedPackage) {
3968 final ApplicationInfo applicationInfo = deletedPackage.applicationInfo;
3969 return applicationInfo.sourceDir.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath());
3970 }
3971
3972 private void extractPublicFiles(PackageParser.Package newPackage,
3973 File publicZipFile) throws IOException {
3974 final ZipOutputStream publicZipOutStream =
3975 new ZipOutputStream(new FileOutputStream(publicZipFile));
3976 final ZipFile privateZip = new ZipFile(newPackage.mPath);
3977
3978 // Copy manifest, resources.arsc and res directory to public zip
3979
3980 final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
3981 while (privateZipEntries.hasMoreElements()) {
3982 final ZipEntry zipEntry = privateZipEntries.nextElement();
3983 final String zipEntryName = zipEntry.getName();
3984 if ("AndroidManifest.xml".equals(zipEntryName)
3985 || "resources.arsc".equals(zipEntryName)
3986 || zipEntryName.startsWith("res/")) {
3987 try {
3988 copyZipEntry(zipEntry, privateZip, publicZipOutStream);
3989 } catch (IOException e) {
3990 try {
3991 publicZipOutStream.close();
3992 throw e;
3993 } finally {
3994 publicZipFile.delete();
3995 }
3996 }
3997 }
3998 }
3999
4000 publicZipOutStream.close();
4001 FileUtils.setPermissions(
4002 publicZipFile.getAbsolutePath(),
4003 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP|FileUtils.S_IROTH,
4004 -1, -1);
4005 }
4006
4007 private static void copyZipEntry(ZipEntry zipEntry,
4008 ZipFile inZipFile,
4009 ZipOutputStream outZipStream) throws IOException {
4010 byte[] buffer = new byte[4096];
4011 int num;
4012
4013 ZipEntry newEntry;
4014 if (zipEntry.getMethod() == ZipEntry.STORED) {
4015 // Preserve the STORED method of the input entry.
4016 newEntry = new ZipEntry(zipEntry);
4017 } else {
4018 // Create a new entry so that the compressed len is recomputed.
4019 newEntry = new ZipEntry(zipEntry.getName());
4020 }
4021 outZipStream.putNextEntry(newEntry);
4022
4023 InputStream data = inZipFile.getInputStream(zipEntry);
4024 while ((num = data.read(buffer)) > 0) {
4025 outZipStream.write(buffer, 0, num);
4026 }
4027 outZipStream.flush();
4028 }
4029
4030 private void deleteTempPackageFiles() {
4031 FilenameFilter filter = new FilenameFilter() {
4032 public boolean accept(File dir, String name) {
4033 return name.startsWith("vmdl") && name.endsWith(".tmp");
4034 }
4035 };
4036 String tmpFilesList[] = mAppInstallDir.list(filter);
4037 if(tmpFilesList == null) {
4038 return;
4039 }
4040 for(int i = 0; i < tmpFilesList.length; i++) {
4041 File tmpFile = new File(mAppInstallDir, tmpFilesList[i]);
4042 tmpFile.delete();
4043 }
4044 }
4045
4046 private File createTempPackageFile() {
4047 File tmpPackageFile;
4048 try {
4049 tmpPackageFile = File.createTempFile("vmdl", ".tmp", mAppInstallDir);
4050 } catch (IOException e) {
4051 Log.e(TAG, "Couldn't create temp file for downloaded package file.");
4052 return null;
4053 }
4054 try {
4055 FileUtils.setPermissions(
4056 tmpPackageFile.getCanonicalPath(), FileUtils.S_IRUSR|FileUtils.S_IWUSR,
4057 -1, -1);
4058 } catch (IOException e) {
4059 Log.e(TAG, "Trouble getting the canoncical path for a temp file.");
4060 return null;
4061 }
4062 return tmpPackageFile;
4063 }
4064
4065 public void deletePackage(final String packageName,
4066 final IPackageDeleteObserver observer,
4067 final int flags) {
4068 mContext.enforceCallingOrSelfPermission(
4069 android.Manifest.permission.DELETE_PACKAGES, null);
4070 // Queue up an async operation since the package deletion may take a little while.
4071 mHandler.post(new Runnable() {
4072 public void run() {
4073 mHandler.removeCallbacks(this);
4074 final boolean succeded = deletePackageX(packageName, true, true, flags);
4075 if (observer != null) {
4076 try {
4077 observer.packageDeleted(succeded);
4078 } catch (RemoteException e) {
4079 Log.i(TAG, "Observer no longer exists.");
4080 } //end catch
4081 } //end if
4082 } //end run
4083 });
4084 }
4085
4086 /**
4087 * This method is an internal method that could be get invoked either
4088 * to delete an installed package or to clean up a failed installation.
4089 * After deleting an installed package, a broadcast is sent to notify any
4090 * listeners that the package has been installed. For cleaning up a failed
4091 * installation, the broadcast is not necessary since the package's
4092 * installation wouldn't have sent the initial broadcast either
4093 * The key steps in deleting a package are
4094 * deleting the package information in internal structures like mPackages,
4095 * deleting the packages base directories through installd
4096 * updating mSettings to reflect current status
4097 * persisting settings for later use
4098 * sending a broadcast if necessary
4099 */
4100
4101 private boolean deletePackageX(String packageName, boolean sendBroadCast,
4102 boolean deleteCodeAndResources, int flags) {
4103 PackageRemovedInfo info = new PackageRemovedInfo();
Romain Guy96f43572009-03-24 20:27:49 -07004104 boolean res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004105
4106 synchronized (mInstallLock) {
4107 res = deletePackageLI(packageName, deleteCodeAndResources, flags, info);
4108 }
4109
4110 if(res && sendBroadCast) {
Romain Guy96f43572009-03-24 20:27:49 -07004111 boolean systemUpdate = info.isRemovedPackageSystemUpdate;
4112 info.sendBroadcast(deleteCodeAndResources, systemUpdate);
4113
4114 // If the removed package was a system update, the old system packaged
4115 // was re-enabled; we need to broadcast this information
4116 if (systemUpdate) {
4117 Bundle extras = new Bundle(1);
4118 extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
4119 extras.putBoolean(Intent.EXTRA_REPLACING, true);
4120
4121 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras);
4122 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras);
4123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004124 }
4125 return res;
4126 }
4127
4128 static class PackageRemovedInfo {
4129 String removedPackage;
4130 int uid = -1;
4131 int removedUid = -1;
Romain Guy96f43572009-03-24 20:27:49 -07004132 boolean isRemovedPackageSystemUpdate = false;
4133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004134 void sendBroadcast(boolean fullRemove, boolean replacing) {
4135 Bundle extras = new Bundle(1);
4136 extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid);
4137 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
4138 if (replacing) {
4139 extras.putBoolean(Intent.EXTRA_REPLACING, true);
4140 }
4141 if (removedPackage != null) {
4142 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
4143 }
4144 if (removedUid >= 0) {
4145 sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras);
4146 }
4147 }
4148 }
4149
4150 /*
4151 * This method deletes the package from internal data structures. If the DONT_DELETE_DATA
4152 * flag is not set, the data directory is removed as well.
4153 * make sure this flag is set for partially installed apps. If not its meaningless to
4154 * delete a partially installed application.
4155 */
4156 private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
4157 int flags) {
4158 String packageName = p.packageName;
4159 outInfo.removedPackage = packageName;
4160 removePackageLI(p, true);
4161 // Retrieve object to delete permissions for shared user later on
4162 PackageSetting deletedPs;
4163 synchronized (mPackages) {
4164 deletedPs = mSettings.mPackages.get(packageName);
4165 }
4166 if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
4167 if (mInstaller != null) {
4168 int retCode = mInstaller.remove(packageName);
4169 if (retCode < 0) {
4170 Log.w(TAG, "Couldn't remove app data or cache directory for package: "
4171 + packageName + ", retcode=" + retCode);
4172 // we don't consider this to be a failure of the core package deletion
4173 }
4174 } else {
4175 //for emulator
4176 PackageParser.Package pkg = mPackages.get(packageName);
4177 File dataDir = new File(pkg.applicationInfo.dataDir);
4178 dataDir.delete();
4179 }
4180 synchronized (mPackages) {
4181 outInfo.removedUid = mSettings.removePackageLP(packageName);
4182 }
4183 }
4184 synchronized (mPackages) {
4185 if ( (deletedPs != null) && (deletedPs.sharedUser != null)) {
4186 // remove permissions associated with package
4187 mSettings.updateSharedUserPerms (deletedPs);
4188 }
4189 // Save settings now
4190 mSettings.writeLP ();
4191 }
4192 }
4193
4194 /*
4195 * Tries to delete system package.
4196 */
4197 private boolean deleteSystemPackageLI(PackageParser.Package p,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004198 int flags, PackageRemovedInfo outInfo) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004199 ApplicationInfo applicationInfo = p.applicationInfo;
4200 //applicable for non-partially installed applications only
4201 if (applicationInfo == null) {
4202 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
4203 return false;
4204 }
4205 PackageSetting ps = null;
4206 // Confirm if the system package has been updated
4207 // An updated system app can be deleted. This will also have to restore
4208 // the system pkg from system partition
4209 synchronized (mPackages) {
4210 ps = mSettings.getDisabledSystemPkg(p.packageName);
4211 }
4212 if (ps == null) {
4213 Log.w(TAG, "Attempt to delete system package "+ p.packageName);
4214 return false;
4215 } else {
4216 Log.i(TAG, "Deleting system pkg from data partition");
4217 }
4218 // Delete the updated package
Romain Guy96f43572009-03-24 20:27:49 -07004219 outInfo.isRemovedPackageSystemUpdate = true;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004220 boolean deleteCodeAndResources = false;
4221 if (ps.versionCode < p.mVersionCode) {
4222 // Delete code and resources for downgrades
4223 deleteCodeAndResources = true;
4224 if ((flags & PackageManager.DONT_DELETE_DATA) == 0) {
4225 flags &= ~PackageManager.DONT_DELETE_DATA;
4226 }
4227 } else {
4228 // Preserve data by setting flag
4229 if ((flags & PackageManager.DONT_DELETE_DATA) == 0) {
4230 flags |= PackageManager.DONT_DELETE_DATA;
4231 }
4232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004233 boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo);
4234 if (!ret) {
4235 return false;
4236 }
4237 synchronized (mPackages) {
4238 // Reinstate the old system package
4239 mSettings.enableSystemPackageLP(p.packageName);
4240 }
4241 // Install the system package
4242 PackageParser.Package newPkg = scanPackageLI(ps.codePath, ps.codePath, ps.resourcePath,
4243 PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
4244 SCAN_MONITOR);
4245
4246 if (newPkg == null) {
4247 Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
4248 return false;
4249 }
4250 synchronized (mPackages) {
Suchi Amalapurapu701f5162009-06-03 15:47:55 -07004251 grantPermissionsLP(newPkg, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004252 mSettings.writeLP();
4253 }
4254 return true;
4255 }
4256
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004257 private void deletePackageResourcesLI(String packageName,
4258 String sourceDir, String publicSourceDir) {
4259 File sourceFile = new File(sourceDir);
4260 if (!sourceFile.exists()) {
4261 Log.w(TAG, "Package source " + sourceDir + " does not exist.");
4262 }
4263 // Delete application's code and resources
4264 sourceFile.delete();
4265 final File publicSourceFile = new File(publicSourceDir);
4266 if (publicSourceFile.exists()) {
4267 publicSourceFile.delete();
4268 }
4269 if (mInstaller != null) {
4270 int retCode = mInstaller.rmdex(sourceFile.toString());
4271 if (retCode < 0) {
4272 Log.w(TAG, "Couldn't remove dex file for package: "
4273 + packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode);
4274 // we don't consider this to be a failure of the core package deletion
4275 }
4276 }
4277 }
4278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004279 private boolean deleteInstalledPackageLI(PackageParser.Package p,
4280 boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
4281 ApplicationInfo applicationInfo = p.applicationInfo;
4282 if (applicationInfo == null) {
4283 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
4284 return false;
4285 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004286 outInfo.uid = applicationInfo.uid;
4287
4288 // Delete package data from internal structures and also remove data if flag is set
4289 removePackageDataLI(p, outInfo, flags);
4290
4291 // Delete application code and resources
4292 if (deleteCodeAndResources) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004293 deletePackageResourcesLI(applicationInfo.packageName,
4294 applicationInfo.sourceDir, applicationInfo.publicSourceDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004295 }
4296 return true;
4297 }
4298
4299 /*
4300 * This method handles package deletion in general
4301 */
4302 private boolean deletePackageLI(String packageName,
4303 boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
4304 if (packageName == null) {
4305 Log.w(TAG, "Attempt to delete null packageName.");
4306 return false;
4307 }
4308 PackageParser.Package p;
4309 boolean dataOnly = false;
4310 synchronized (mPackages) {
4311 p = mPackages.get(packageName);
4312 if (p == null) {
4313 //this retrieves partially installed apps
4314 dataOnly = true;
4315 PackageSetting ps = mSettings.mPackages.get(packageName);
4316 if (ps == null) {
4317 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4318 return false;
4319 }
4320 p = ps.pkg;
4321 }
4322 }
4323 if (p == null) {
4324 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4325 return false;
4326 }
4327
4328 if (dataOnly) {
4329 // Delete application data first
4330 removePackageDataLI(p, outInfo, flags);
4331 return true;
4332 }
4333 // At this point the package should have ApplicationInfo associated with it
4334 if (p.applicationInfo == null) {
4335 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
4336 return false;
4337 }
4338 if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
4339 Log.i(TAG, "Removing system package:"+p.packageName);
4340 // When an updated system application is deleted we delete the existing resources as well and
4341 // fall back to existing code in system partition
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004342 return deleteSystemPackageLI(p, flags, outInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004343 }
4344 Log.i(TAG, "Removing non-system package:"+p.packageName);
4345 return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
4346 }
4347
4348 public void clearApplicationUserData(final String packageName,
4349 final IPackageDataObserver observer) {
4350 mContext.enforceCallingOrSelfPermission(
4351 android.Manifest.permission.CLEAR_APP_USER_DATA, null);
4352 // Queue up an async operation since the package deletion may take a little while.
4353 mHandler.post(new Runnable() {
4354 public void run() {
4355 mHandler.removeCallbacks(this);
4356 final boolean succeeded;
4357 synchronized (mInstallLock) {
4358 succeeded = clearApplicationUserDataLI(packageName);
4359 }
4360 if (succeeded) {
4361 // invoke DeviceStorageMonitor's update method to clear any notifications
4362 DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
4363 ServiceManager.getService(DeviceStorageMonitorService.SERVICE);
4364 if (dsm != null) {
4365 dsm.updateMemory();
4366 }
4367 }
4368 if(observer != null) {
4369 try {
4370 observer.onRemoveCompleted(packageName, succeeded);
4371 } catch (RemoteException e) {
4372 Log.i(TAG, "Observer no longer exists.");
4373 }
4374 } //end if observer
4375 } //end run
4376 });
4377 }
4378
4379 private boolean clearApplicationUserDataLI(String packageName) {
4380 if (packageName == null) {
4381 Log.w(TAG, "Attempt to delete null packageName.");
4382 return false;
4383 }
4384 PackageParser.Package p;
4385 boolean dataOnly = false;
4386 synchronized (mPackages) {
4387 p = mPackages.get(packageName);
4388 if(p == null) {
4389 dataOnly = true;
4390 PackageSetting ps = mSettings.mPackages.get(packageName);
4391 if((ps == null) || (ps.pkg == null)) {
4392 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4393 return false;
4394 }
4395 p = ps.pkg;
4396 }
4397 }
4398 if(!dataOnly) {
4399 //need to check this only for fully installed applications
4400 if (p == null) {
4401 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4402 return false;
4403 }
4404 final ApplicationInfo applicationInfo = p.applicationInfo;
4405 if (applicationInfo == null) {
4406 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
4407 return false;
4408 }
4409 }
4410 if (mInstaller != null) {
4411 int retCode = mInstaller.clearUserData(packageName);
4412 if (retCode < 0) {
4413 Log.w(TAG, "Couldn't remove cache files for package: "
4414 + packageName);
4415 return false;
4416 }
4417 }
4418 return true;
4419 }
4420
4421 public void deleteApplicationCacheFiles(final String packageName,
4422 final IPackageDataObserver observer) {
4423 mContext.enforceCallingOrSelfPermission(
4424 android.Manifest.permission.DELETE_CACHE_FILES, null);
4425 // Queue up an async operation since the package deletion may take a little while.
4426 mHandler.post(new Runnable() {
4427 public void run() {
4428 mHandler.removeCallbacks(this);
4429 final boolean succeded;
4430 synchronized (mInstallLock) {
4431 succeded = deleteApplicationCacheFilesLI(packageName);
4432 }
4433 if(observer != null) {
4434 try {
4435 observer.onRemoveCompleted(packageName, succeded);
4436 } catch (RemoteException e) {
4437 Log.i(TAG, "Observer no longer exists.");
4438 }
4439 } //end if observer
4440 } //end run
4441 });
4442 }
4443
4444 private boolean deleteApplicationCacheFilesLI(String packageName) {
4445 if (packageName == null) {
4446 Log.w(TAG, "Attempt to delete null packageName.");
4447 return false;
4448 }
4449 PackageParser.Package p;
4450 synchronized (mPackages) {
4451 p = mPackages.get(packageName);
4452 }
4453 if (p == null) {
4454 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4455 return false;
4456 }
4457 final ApplicationInfo applicationInfo = p.applicationInfo;
4458 if (applicationInfo == null) {
4459 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
4460 return false;
4461 }
4462 if (mInstaller != null) {
4463 int retCode = mInstaller.deleteCacheFiles(packageName);
4464 if (retCode < 0) {
4465 Log.w(TAG, "Couldn't remove cache files for package: "
4466 + packageName);
4467 return false;
4468 }
4469 }
4470 return true;
4471 }
4472
4473 public void getPackageSizeInfo(final String packageName,
4474 final IPackageStatsObserver observer) {
4475 mContext.enforceCallingOrSelfPermission(
4476 android.Manifest.permission.GET_PACKAGE_SIZE, null);
4477 // Queue up an async operation since the package deletion may take a little while.
4478 mHandler.post(new Runnable() {
4479 public void run() {
4480 mHandler.removeCallbacks(this);
4481 PackageStats lStats = new PackageStats(packageName);
4482 final boolean succeded;
4483 synchronized (mInstallLock) {
4484 succeded = getPackageSizeInfoLI(packageName, lStats);
4485 }
4486 if(observer != null) {
4487 try {
4488 observer.onGetStatsCompleted(lStats, succeded);
4489 } catch (RemoteException e) {
4490 Log.i(TAG, "Observer no longer exists.");
4491 }
4492 } //end if observer
4493 } //end run
4494 });
4495 }
4496
4497 private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) {
4498 if (packageName == null) {
4499 Log.w(TAG, "Attempt to get size of null packageName.");
4500 return false;
4501 }
4502 PackageParser.Package p;
4503 boolean dataOnly = false;
4504 synchronized (mPackages) {
4505 p = mPackages.get(packageName);
4506 if(p == null) {
4507 dataOnly = true;
4508 PackageSetting ps = mSettings.mPackages.get(packageName);
4509 if((ps == null) || (ps.pkg == null)) {
4510 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
4511 return false;
4512 }
4513 p = ps.pkg;
4514 }
4515 }
4516 String publicSrcDir = null;
4517 if(!dataOnly) {
4518 final ApplicationInfo applicationInfo = p.applicationInfo;
4519 if (applicationInfo == null) {
4520 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
4521 return false;
4522 }
4523 publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
4524 }
4525 if (mInstaller != null) {
4526 int res = mInstaller.getSizeInfo(packageName, p.mPath,
4527 publicSrcDir, pStats);
4528 if (res < 0) {
4529 return false;
4530 } else {
4531 return true;
4532 }
4533 }
4534 return true;
4535 }
4536
4537
4538 public void addPackageToPreferred(String packageName) {
4539 mContext.enforceCallingOrSelfPermission(
4540 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4541
4542 synchronized (mPackages) {
4543 PackageParser.Package p = mPackages.get(packageName);
4544 if (p == null) {
4545 return;
4546 }
4547 PackageSetting ps = (PackageSetting)p.mExtras;
4548 if (ps != null) {
4549 mSettings.mPreferredPackages.remove(ps);
4550 mSettings.mPreferredPackages.add(0, ps);
4551 updatePreferredIndicesLP();
4552 mSettings.writeLP();
4553 }
4554 }
4555 }
4556
4557 public void removePackageFromPreferred(String packageName) {
4558 mContext.enforceCallingOrSelfPermission(
4559 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4560
4561 synchronized (mPackages) {
4562 PackageParser.Package p = mPackages.get(packageName);
4563 if (p == null) {
4564 return;
4565 }
4566 if (p.mPreferredOrder > 0) {
4567 PackageSetting ps = (PackageSetting)p.mExtras;
4568 if (ps != null) {
4569 mSettings.mPreferredPackages.remove(ps);
4570 p.mPreferredOrder = 0;
4571 updatePreferredIndicesLP();
4572 mSettings.writeLP();
4573 }
4574 }
4575 }
4576 }
4577
4578 private void updatePreferredIndicesLP() {
4579 final ArrayList<PackageSetting> pkgs
4580 = mSettings.mPreferredPackages;
4581 final int N = pkgs.size();
4582 for (int i=0; i<N; i++) {
4583 pkgs.get(i).pkg.mPreferredOrder = N - i;
4584 }
4585 }
4586
4587 public List<PackageInfo> getPreferredPackages(int flags) {
4588 synchronized (mPackages) {
4589 final ArrayList<PackageInfo> res = new ArrayList<PackageInfo>();
4590 final ArrayList<PackageSetting> pref = mSettings.mPreferredPackages;
4591 final int N = pref.size();
4592 for (int i=0; i<N; i++) {
4593 res.add(generatePackageInfo(pref.get(i).pkg, flags));
4594 }
4595 return res;
4596 }
4597 }
4598
4599 public void addPreferredActivity(IntentFilter filter, int match,
4600 ComponentName[] set, ComponentName activity) {
4601 mContext.enforceCallingOrSelfPermission(
4602 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4603
4604 synchronized (mPackages) {
4605 Log.i(TAG, "Adding preferred activity " + activity + ":");
4606 filter.dump(new LogPrinter(Log.INFO, TAG), " ");
4607 mSettings.mPreferredActivities.addFilter(
4608 new PreferredActivity(filter, match, set, activity));
4609 mSettings.writeLP();
4610 }
4611 }
4612
Satish Sampath8dbe6122009-06-02 23:35:54 +01004613 public void replacePreferredActivity(IntentFilter filter, int match,
4614 ComponentName[] set, ComponentName activity) {
4615 mContext.enforceCallingOrSelfPermission(
4616 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4617 if (filter.countActions() != 1) {
4618 throw new IllegalArgumentException(
4619 "replacePreferredActivity expects filter to have only 1 action.");
4620 }
4621 if (filter.countCategories() != 1) {
4622 throw new IllegalArgumentException(
4623 "replacePreferredActivity expects filter to have only 1 category.");
4624 }
4625 if (filter.countDataAuthorities() != 0
4626 || filter.countDataPaths() != 0
4627 || filter.countDataSchemes() != 0
4628 || filter.countDataTypes() != 0) {
4629 throw new IllegalArgumentException(
4630 "replacePreferredActivity expects filter to have no data authorities, " +
4631 "paths, schemes or types.");
4632 }
4633 synchronized (mPackages) {
4634 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
4635 String action = filter.getAction(0);
4636 String category = filter.getCategory(0);
4637 while (it.hasNext()) {
4638 PreferredActivity pa = it.next();
4639 if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
4640 it.remove();
4641 Log.i(TAG, "Removed preferred activity " + pa.mActivity + ":");
4642 filter.dump(new LogPrinter(Log.INFO, TAG), " ");
4643 }
4644 }
4645 addPreferredActivity(filter, match, set, activity);
4646 }
4647 }
4648
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004649 public void clearPackagePreferredActivities(String packageName) {
4650 mContext.enforceCallingOrSelfPermission(
4651 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
4652
4653 synchronized (mPackages) {
4654 if (clearPackagePreferredActivitiesLP(packageName)) {
4655 mSettings.writeLP();
4656 }
4657 }
4658 }
4659
4660 boolean clearPackagePreferredActivitiesLP(String packageName) {
4661 boolean changed = false;
4662 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
4663 while (it.hasNext()) {
4664 PreferredActivity pa = it.next();
4665 if (pa.mActivity.getPackageName().equals(packageName)) {
4666 it.remove();
4667 changed = true;
4668 }
4669 }
4670 return changed;
4671 }
4672
4673 public int getPreferredActivities(List<IntentFilter> outFilters,
4674 List<ComponentName> outActivities, String packageName) {
4675
4676 int num = 0;
4677 synchronized (mPackages) {
4678 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
4679 while (it.hasNext()) {
4680 PreferredActivity pa = it.next();
4681 if (packageName == null
4682 || pa.mActivity.getPackageName().equals(packageName)) {
4683 if (outFilters != null) {
4684 outFilters.add(new IntentFilter(pa));
4685 }
4686 if (outActivities != null) {
4687 outActivities.add(pa.mActivity);
4688 }
4689 }
4690 }
4691 }
4692
4693 return num;
4694 }
4695
4696 public void setApplicationEnabledSetting(String appPackageName,
4697 int newState, int flags) {
4698 setEnabledSetting(appPackageName, null, newState, flags);
4699 }
4700
4701 public void setComponentEnabledSetting(ComponentName componentName,
4702 int newState, int flags) {
4703 setEnabledSetting(componentName.getPackageName(),
4704 componentName.getClassName(), newState, flags);
4705 }
4706
4707 private void setEnabledSetting(
4708 final String packageNameStr, String classNameStr, int newState, final int flags) {
4709 if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
4710 || newState == COMPONENT_ENABLED_STATE_ENABLED
4711 || newState == COMPONENT_ENABLED_STATE_DISABLED)) {
4712 throw new IllegalArgumentException("Invalid new component state: "
4713 + newState);
4714 }
4715 PackageSetting pkgSetting;
4716 final int uid = Binder.getCallingUid();
4717 final int permission = mContext.checkCallingPermission(
4718 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
4719 final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
4720 int packageUid = -1;
4721 synchronized (mPackages) {
4722 pkgSetting = mSettings.mPackages.get(packageNameStr);
4723 if (pkgSetting == null) {
4724 if (classNameStr == null) {
4725 throw new IllegalArgumentException(
4726 "Unknown package: " + packageNameStr);
4727 }
4728 throw new IllegalArgumentException(
4729 "Unknown component: " + packageNameStr
4730 + "/" + classNameStr);
4731 }
4732 if (!allowedByPermission && (uid != pkgSetting.userId)) {
4733 throw new SecurityException(
4734 "Permission Denial: attempt to change component state from pid="
4735 + Binder.getCallingPid()
4736 + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
4737 }
4738 packageUid = pkgSetting.userId;
4739 if (classNameStr == null) {
4740 // We're dealing with an application/package level state change
4741 pkgSetting.enabled = newState;
4742 } else {
4743 // We're dealing with a component level state change
4744 switch (newState) {
4745 case COMPONENT_ENABLED_STATE_ENABLED:
4746 pkgSetting.enableComponentLP(classNameStr);
4747 break;
4748 case COMPONENT_ENABLED_STATE_DISABLED:
4749 pkgSetting.disableComponentLP(classNameStr);
4750 break;
4751 case COMPONENT_ENABLED_STATE_DEFAULT:
4752 pkgSetting.restoreComponentLP(classNameStr);
4753 break;
4754 default:
4755 Log.e(TAG, "Invalid new component state: " + newState);
4756 }
4757 }
4758 mSettings.writeLP();
4759 }
4760
4761 long callingId = Binder.clearCallingIdentity();
4762 try {
4763 Bundle extras = new Bundle(2);
4764 extras.putBoolean(Intent.EXTRA_DONT_KILL_APP,
4765 (flags&PackageManager.DONT_KILL_APP) != 0);
4766 extras.putInt(Intent.EXTRA_UID, packageUid);
4767 sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageNameStr, extras);
4768 } finally {
4769 Binder.restoreCallingIdentity(callingId);
4770 }
4771 }
4772
Jacek Surazskic64322c2009-04-28 15:26:38 +02004773 public String getInstallerPackageName(String packageName) {
4774 synchronized (mPackages) {
4775 PackageSetting pkg = mSettings.mPackages.get(packageName);
4776 if (pkg == null) {
4777 throw new IllegalArgumentException("Unknown package: " + packageName);
4778 }
4779 return pkg.installerPackageName;
4780 }
4781 }
4782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004783 public int getApplicationEnabledSetting(String appPackageName) {
4784 synchronized (mPackages) {
4785 PackageSetting pkg = mSettings.mPackages.get(appPackageName);
4786 if (pkg == null) {
4787 throw new IllegalArgumentException("Unknown package: " + appPackageName);
4788 }
4789 return pkg.enabled;
4790 }
4791 }
4792
4793 public int getComponentEnabledSetting(ComponentName componentName) {
4794 synchronized (mPackages) {
4795 final String packageNameStr = componentName.getPackageName();
4796 PackageSetting pkg = mSettings.mPackages.get(packageNameStr);
4797 if (pkg == null) {
4798 throw new IllegalArgumentException("Unknown component: " + componentName);
4799 }
4800 final String classNameStr = componentName.getClassName();
4801 return pkg.currentEnabledStateLP(classNameStr);
4802 }
4803 }
4804
4805 public void enterSafeMode() {
4806 if (!mSystemReady) {
4807 mSafeMode = true;
4808 }
4809 }
4810
4811 public void systemReady() {
4812 mSystemReady = true;
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07004813
4814 // Read the compatibilty setting when the system is ready.
4815 mCompatibilityModeEnabled = android.provider.Settings.System.getInt(
4816 mContext.getContentResolver(),
4817 android.provider.Settings.System.COMPATIBILITY_MODE, 1) == 1;
4818 if (DEBUG_SETTINGS) {
4819 Log.d(TAG, "compatibility mode:" + mCompatibilityModeEnabled);
4820 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004821 }
4822
4823 public boolean isSafeMode() {
4824 return mSafeMode;
4825 }
4826
4827 public boolean hasSystemUidErrors() {
4828 return mHasSystemUidErrors;
4829 }
4830
4831 static String arrayToString(int[] array) {
4832 StringBuffer buf = new StringBuffer(128);
4833 buf.append('[');
4834 if (array != null) {
4835 for (int i=0; i<array.length; i++) {
4836 if (i > 0) buf.append(", ");
4837 buf.append(array[i]);
4838 }
4839 }
4840 buf.append(']');
4841 return buf.toString();
4842 }
4843
4844 @Override
4845 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4846 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
4847 != PackageManager.PERMISSION_GRANTED) {
4848 pw.println("Permission Denial: can't dump ActivityManager from from pid="
4849 + Binder.getCallingPid()
4850 + ", uid=" + Binder.getCallingUid()
4851 + " without permission "
4852 + android.Manifest.permission.DUMP);
4853 return;
4854 }
4855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004856 synchronized (mPackages) {
4857 pw.println("Activity Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004858 mActivities.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004859 pw.println(" ");
4860 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004861 mReceivers.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004862 pw.println(" ");
4863 pw.println("Service Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004864 mServices.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004865 pw.println(" ");
4866 pw.println("Preferred Activities:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004867 mSettings.mPreferredActivities.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004868 pw.println(" ");
4869 pw.println("Preferred Packages:");
4870 {
4871 for (PackageSetting ps : mSettings.mPreferredPackages) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004872 pw.print(" "); pw.println(ps.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004873 }
4874 }
4875 pw.println(" ");
4876 pw.println("Permissions:");
4877 {
4878 for (BasePermission p : mSettings.mPermissions.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004879 pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
4880 pw.print(Integer.toHexString(System.identityHashCode(p)));
4881 pw.println("):");
4882 pw.print(" sourcePackage="); pw.println(p.sourcePackage);
4883 pw.print(" uid="); pw.print(p.uid);
4884 pw.print(" gids="); pw.print(arrayToString(p.gids));
4885 pw.print(" type="); pw.println(p.type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004886 }
4887 }
4888 pw.println(" ");
4889 pw.println("Packages:");
4890 {
4891 for (PackageSetting ps : mSettings.mPackages.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004892 pw.print(" Package ["); pw.print(ps.name); pw.print("] (");
4893 pw.print(Integer.toHexString(System.identityHashCode(ps)));
4894 pw.println("):");
4895 pw.print(" userId="); pw.print(ps.userId);
4896 pw.print(" gids="); pw.println(arrayToString(ps.gids));
4897 pw.print(" sharedUser="); pw.println(ps.sharedUser);
4898 pw.print(" pkg="); pw.println(ps.pkg);
4899 pw.print(" codePath="); pw.println(ps.codePathString);
4900 pw.print(" resourcePath="); pw.println(ps.resourcePathString);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004901 if (ps.pkg != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004902 pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004903 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004904 pw.print(" timeStamp="); pw.println(ps.getTimeStampStr());
4905 pw.print(" signatures="); pw.println(ps.signatures);
4906 pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
4907 pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
4908 pw.print(" installStatus="); pw.print(ps.installStatus);
4909 pw.print(" enabled="); pw.println(ps.enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004910 if (ps.disabledComponents.size() > 0) {
4911 pw.println(" disabledComponents:");
4912 for (String s : ps.disabledComponents) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004913 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004914 }
4915 }
4916 if (ps.enabledComponents.size() > 0) {
4917 pw.println(" enabledComponents:");
4918 for (String s : ps.enabledComponents) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004919 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004920 }
4921 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004922 if (ps.grantedPermissions.size() > 0) {
4923 pw.println(" grantedPermissions:");
4924 for (String s : ps.grantedPermissions) {
4925 pw.print(" "); pw.println(s);
4926 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004927 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004928 if (ps.loadedPermissions.size() > 0) {
4929 pw.println(" loadedPermissions:");
4930 for (String s : ps.loadedPermissions) {
4931 pw.print(" "); pw.println(s);
4932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004933 }
4934 }
4935 }
4936 pw.println(" ");
4937 pw.println("Shared Users:");
4938 {
4939 for (SharedUserSetting su : mSettings.mSharedUsers.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004940 pw.print(" SharedUser ["); pw.print(su.name); pw.print("] (");
4941 pw.print(Integer.toHexString(System.identityHashCode(su)));
4942 pw.println("):");
4943 pw.print(" userId="); pw.print(su.userId);
4944 pw.print(" gids="); pw.println(arrayToString(su.gids));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004945 pw.println(" grantedPermissions:");
4946 for (String s : su.grantedPermissions) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004947 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004948 }
4949 pw.println(" loadedPermissions:");
4950 for (String s : su.loadedPermissions) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004951 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004952 }
4953 }
4954 }
4955 pw.println(" ");
4956 pw.println("Settings parse messages:");
4957 pw.println(mSettings.mReadMessages.toString());
4958 }
4959 }
4960
4961 static final class BasePermission {
4962 final static int TYPE_NORMAL = 0;
4963 final static int TYPE_BUILTIN = 1;
4964 final static int TYPE_DYNAMIC = 2;
4965
4966 final String name;
4967 final String sourcePackage;
4968 final int type;
4969 PackageParser.Permission perm;
4970 PermissionInfo pendingInfo;
4971 int uid;
4972 int[] gids;
4973
4974 BasePermission(String _name, String _sourcePackage, int _type) {
4975 name = _name;
4976 sourcePackage = _sourcePackage;
4977 type = _type;
4978 }
4979 }
4980
4981 static class PackageSignatures {
4982 private Signature[] mSignatures;
4983
4984 PackageSignatures(Signature[] sigs) {
4985 assignSignatures(sigs);
4986 }
4987
4988 PackageSignatures() {
4989 }
4990
4991 void writeXml(XmlSerializer serializer, String tagName,
4992 ArrayList<Signature> pastSignatures) throws IOException {
4993 if (mSignatures == null) {
4994 return;
4995 }
4996 serializer.startTag(null, tagName);
4997 serializer.attribute(null, "count",
4998 Integer.toString(mSignatures.length));
4999 for (int i=0; i<mSignatures.length; i++) {
5000 serializer.startTag(null, "cert");
5001 final Signature sig = mSignatures[i];
5002 final int sigHash = sig.hashCode();
5003 final int numPast = pastSignatures.size();
5004 int j;
5005 for (j=0; j<numPast; j++) {
5006 Signature pastSig = pastSignatures.get(j);
5007 if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
5008 serializer.attribute(null, "index", Integer.toString(j));
5009 break;
5010 }
5011 }
5012 if (j >= numPast) {
5013 pastSignatures.add(sig);
5014 serializer.attribute(null, "index", Integer.toString(numPast));
5015 serializer.attribute(null, "key", sig.toCharsString());
5016 }
5017 serializer.endTag(null, "cert");
5018 }
5019 serializer.endTag(null, tagName);
5020 }
5021
5022 void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
5023 throws IOException, XmlPullParserException {
5024 String countStr = parser.getAttributeValue(null, "count");
5025 if (countStr == null) {
5026 reportSettingsProblem(Log.WARN,
5027 "Error in package manager settings: <signatures> has"
5028 + " no count at " + parser.getPositionDescription());
5029 XmlUtils.skipCurrentTag(parser);
5030 }
5031 final int count = Integer.parseInt(countStr);
5032 mSignatures = new Signature[count];
5033 int pos = 0;
5034
5035 int outerDepth = parser.getDepth();
5036 int type;
5037 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
5038 && (type != XmlPullParser.END_TAG
5039 || parser.getDepth() > outerDepth)) {
5040 if (type == XmlPullParser.END_TAG
5041 || type == XmlPullParser.TEXT) {
5042 continue;
5043 }
5044
5045 String tagName = parser.getName();
5046 if (tagName.equals("cert")) {
5047 if (pos < count) {
5048 String index = parser.getAttributeValue(null, "index");
5049 if (index != null) {
5050 try {
5051 int idx = Integer.parseInt(index);
5052 String key = parser.getAttributeValue(null, "key");
5053 if (key == null) {
5054 if (idx >= 0 && idx < pastSignatures.size()) {
5055 Signature sig = pastSignatures.get(idx);
5056 if (sig != null) {
5057 mSignatures[pos] = pastSignatures.get(idx);
5058 pos++;
5059 } else {
5060 reportSettingsProblem(Log.WARN,
5061 "Error in package manager settings: <cert> "
5062 + "index " + index + " is not defined at "
5063 + parser.getPositionDescription());
5064 }
5065 } else {
5066 reportSettingsProblem(Log.WARN,
5067 "Error in package manager settings: <cert> "
5068 + "index " + index + " is out of bounds at "
5069 + parser.getPositionDescription());
5070 }
5071 } else {
5072 while (pastSignatures.size() <= idx) {
5073 pastSignatures.add(null);
5074 }
5075 Signature sig = new Signature(key);
5076 pastSignatures.set(idx, sig);
5077 mSignatures[pos] = sig;
5078 pos++;
5079 }
5080 } catch (NumberFormatException e) {
5081 reportSettingsProblem(Log.WARN,
5082 "Error in package manager settings: <cert> "
5083 + "index " + index + " is not a number at "
5084 + parser.getPositionDescription());
5085 }
5086 } else {
5087 reportSettingsProblem(Log.WARN,
5088 "Error in package manager settings: <cert> has"
5089 + " no index at " + parser.getPositionDescription());
5090 }
5091 } else {
5092 reportSettingsProblem(Log.WARN,
5093 "Error in package manager settings: too "
5094 + "many <cert> tags, expected " + count
5095 + " at " + parser.getPositionDescription());
5096 }
5097 } else {
5098 reportSettingsProblem(Log.WARN,
5099 "Unknown element under <cert>: "
5100 + parser.getName());
5101 }
5102 XmlUtils.skipCurrentTag(parser);
5103 }
5104
5105 if (pos < count) {
5106 // Should never happen -- there is an error in the written
5107 // settings -- but if it does we don't want to generate
5108 // a bad array.
5109 Signature[] newSigs = new Signature[pos];
5110 System.arraycopy(mSignatures, 0, newSigs, 0, pos);
5111 mSignatures = newSigs;
5112 }
5113 }
5114
5115 /**
5116 * If any of the given 'sigs' is contained in the existing signatures,
5117 * then completely replace the current signatures with the ones in
5118 * 'sigs'. This is used for updating an existing package to a newly
5119 * installed version.
5120 */
5121 boolean updateSignatures(Signature[] sigs, boolean update) {
5122 if (mSignatures == null) {
5123 if (update) {
5124 assignSignatures(sigs);
5125 }
5126 return true;
5127 }
5128 if (sigs == null) {
5129 return false;
5130 }
5131
5132 for (int i=0; i<sigs.length; i++) {
5133 Signature sig = sigs[i];
5134 for (int j=0; j<mSignatures.length; j++) {
5135 if (mSignatures[j].equals(sig)) {
5136 if (update) {
5137 assignSignatures(sigs);
5138 }
5139 return true;
5140 }
5141 }
5142 }
5143 return false;
5144 }
5145
5146 /**
5147 * If any of the given 'sigs' is contained in the existing signatures,
5148 * then add in any new signatures found in 'sigs'. This is used for
5149 * including a new package into an existing shared user id.
5150 */
5151 boolean mergeSignatures(Signature[] sigs, boolean update) {
5152 if (mSignatures == null) {
5153 if (update) {
5154 assignSignatures(sigs);
5155 }
5156 return true;
5157 }
5158 if (sigs == null) {
5159 return false;
5160 }
5161
5162 Signature[] added = null;
5163 int addedCount = 0;
5164 boolean haveMatch = false;
5165 for (int i=0; i<sigs.length; i++) {
5166 Signature sig = sigs[i];
5167 boolean found = false;
5168 for (int j=0; j<mSignatures.length; j++) {
5169 if (mSignatures[j].equals(sig)) {
5170 found = true;
5171 haveMatch = true;
5172 break;
5173 }
5174 }
5175
5176 if (!found) {
5177 if (added == null) {
5178 added = new Signature[sigs.length];
5179 }
5180 added[i] = sig;
5181 addedCount++;
5182 }
5183 }
5184
5185 if (!haveMatch) {
5186 // Nothing matched -- reject the new signatures.
5187 return false;
5188 }
5189 if (added == null) {
5190 // Completely matched -- nothing else to do.
5191 return true;
5192 }
5193
5194 // Add additional signatures in.
5195 if (update) {
5196 Signature[] total = new Signature[addedCount+mSignatures.length];
5197 System.arraycopy(mSignatures, 0, total, 0, mSignatures.length);
5198 int j = mSignatures.length;
5199 for (int i=0; i<added.length; i++) {
5200 if (added[i] != null) {
5201 total[j] = added[i];
5202 j++;
5203 }
5204 }
5205 mSignatures = total;
5206 }
5207 return true;
5208 }
5209
5210 private void assignSignatures(Signature[] sigs) {
5211 if (sigs == null) {
5212 mSignatures = null;
5213 return;
5214 }
5215 mSignatures = new Signature[sigs.length];
5216 for (int i=0; i<sigs.length; i++) {
5217 mSignatures[i] = sigs[i];
5218 }
5219 }
5220
5221 @Override
5222 public String toString() {
5223 StringBuffer buf = new StringBuffer(128);
5224 buf.append("PackageSignatures{");
5225 buf.append(Integer.toHexString(System.identityHashCode(this)));
5226 buf.append(" [");
5227 if (mSignatures != null) {
5228 for (int i=0; i<mSignatures.length; i++) {
5229 if (i > 0) buf.append(", ");
5230 buf.append(Integer.toHexString(
5231 System.identityHashCode(mSignatures[i])));
5232 }
5233 }
5234 buf.append("]}");
5235 return buf.toString();
5236 }
5237 }
5238
5239 static class PreferredActivity extends IntentFilter {
5240 final int mMatch;
5241 final String[] mSetPackages;
5242 final String[] mSetClasses;
5243 final String[] mSetComponents;
5244 final ComponentName mActivity;
5245 final String mShortActivity;
5246 String mParseError;
5247
5248 PreferredActivity(IntentFilter filter, int match, ComponentName[] set,
5249 ComponentName activity) {
5250 super(filter);
5251 mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
5252 mActivity = activity;
5253 mShortActivity = activity.flattenToShortString();
5254 mParseError = null;
5255 if (set != null) {
5256 final int N = set.length;
5257 String[] myPackages = new String[N];
5258 String[] myClasses = new String[N];
5259 String[] myComponents = new String[N];
5260 for (int i=0; i<N; i++) {
5261 ComponentName cn = set[i];
5262 if (cn == null) {
5263 mSetPackages = null;
5264 mSetClasses = null;
5265 mSetComponents = null;
5266 return;
5267 }
5268 myPackages[i] = cn.getPackageName().intern();
5269 myClasses[i] = cn.getClassName().intern();
5270 myComponents[i] = cn.flattenToShortString().intern();
5271 }
5272 mSetPackages = myPackages;
5273 mSetClasses = myClasses;
5274 mSetComponents = myComponents;
5275 } else {
5276 mSetPackages = null;
5277 mSetClasses = null;
5278 mSetComponents = null;
5279 }
5280 }
5281
5282 PreferredActivity(XmlPullParser parser) throws XmlPullParserException,
5283 IOException {
5284 mShortActivity = parser.getAttributeValue(null, "name");
5285 mActivity = ComponentName.unflattenFromString(mShortActivity);
5286 if (mActivity == null) {
5287 mParseError = "Bad activity name " + mShortActivity;
5288 }
5289 String matchStr = parser.getAttributeValue(null, "match");
5290 mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
5291 String setCountStr = parser.getAttributeValue(null, "set");
5292 int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
5293
5294 String[] myPackages = setCount > 0 ? new String[setCount] : null;
5295 String[] myClasses = setCount > 0 ? new String[setCount] : null;
5296 String[] myComponents = setCount > 0 ? new String[setCount] : null;
5297
5298 int setPos = 0;
5299
5300 int outerDepth = parser.getDepth();
5301 int type;
5302 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
5303 && (type != XmlPullParser.END_TAG
5304 || parser.getDepth() > outerDepth)) {
5305 if (type == XmlPullParser.END_TAG
5306 || type == XmlPullParser.TEXT) {
5307 continue;
5308 }
5309
5310 String tagName = parser.getName();
5311 //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth="
5312 // + parser.getDepth() + " tag=" + tagName);
5313 if (tagName.equals("set")) {
5314 String name = parser.getAttributeValue(null, "name");
5315 if (name == null) {
5316 if (mParseError == null) {
5317 mParseError = "No name in set tag in preferred activity "
5318 + mShortActivity;
5319 }
5320 } else if (setPos >= setCount) {
5321 if (mParseError == null) {
5322 mParseError = "Too many set tags in preferred activity "
5323 + mShortActivity;
5324 }
5325 } else {
5326 ComponentName cn = ComponentName.unflattenFromString(name);
5327 if (cn == null) {
5328 if (mParseError == null) {
5329 mParseError = "Bad set name " + name + " in preferred activity "
5330 + mShortActivity;
5331 }
5332 } else {
5333 myPackages[setPos] = cn.getPackageName();
5334 myClasses[setPos] = cn.getClassName();
5335 myComponents[setPos] = name;
5336 setPos++;
5337 }
5338 }
5339 XmlUtils.skipCurrentTag(parser);
5340 } else if (tagName.equals("filter")) {
5341 //Log.i(TAG, "Starting to parse filter...");
5342 readFromXml(parser);
5343 //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth="
5344 // + parser.getDepth() + " tag=" + parser.getName());
5345 } else {
5346 reportSettingsProblem(Log.WARN,
5347 "Unknown element under <preferred-activities>: "
5348 + parser.getName());
5349 XmlUtils.skipCurrentTag(parser);
5350 }
5351 }
5352
5353 if (setPos != setCount) {
5354 if (mParseError == null) {
5355 mParseError = "Not enough set tags (expected " + setCount
5356 + " but found " + setPos + ") in " + mShortActivity;
5357 }
5358 }
5359
5360 mSetPackages = myPackages;
5361 mSetClasses = myClasses;
5362 mSetComponents = myComponents;
5363 }
5364
5365 public void writeToXml(XmlSerializer serializer) throws IOException {
5366 final int NS = mSetClasses != null ? mSetClasses.length : 0;
5367 serializer.attribute(null, "name", mShortActivity);
5368 serializer.attribute(null, "match", Integer.toHexString(mMatch));
5369 serializer.attribute(null, "set", Integer.toString(NS));
5370 for (int s=0; s<NS; s++) {
5371 serializer.startTag(null, "set");
5372 serializer.attribute(null, "name", mSetComponents[s]);
5373 serializer.endTag(null, "set");
5374 }
5375 serializer.startTag(null, "filter");
5376 super.writeToXml(serializer);
5377 serializer.endTag(null, "filter");
5378 }
5379
5380 boolean sameSet(List<ResolveInfo> query, int priority) {
5381 if (mSetPackages == null) return false;
5382 final int NQ = query.size();
5383 final int NS = mSetPackages.length;
5384 int numMatch = 0;
5385 for (int i=0; i<NQ; i++) {
5386 ResolveInfo ri = query.get(i);
5387 if (ri.priority != priority) continue;
5388 ActivityInfo ai = ri.activityInfo;
5389 boolean good = false;
5390 for (int j=0; j<NS; j++) {
5391 if (mSetPackages[j].equals(ai.packageName)
5392 && mSetClasses[j].equals(ai.name)) {
5393 numMatch++;
5394 good = true;
5395 break;
5396 }
5397 }
5398 if (!good) return false;
5399 }
5400 return numMatch == NS;
5401 }
5402 }
5403
5404 static class GrantedPermissions {
5405 final int pkgFlags;
5406
5407 HashSet<String> grantedPermissions = new HashSet<String>();
5408 int[] gids;
5409
5410 HashSet<String> loadedPermissions = new HashSet<String>();
5411
5412 GrantedPermissions(int pkgFlags) {
5413 this.pkgFlags = pkgFlags & ApplicationInfo.FLAG_SYSTEM;
5414 }
5415 }
5416
5417 /**
5418 * Settings base class for pending and resolved classes.
5419 */
5420 static class PackageSettingBase extends GrantedPermissions {
5421 final String name;
5422 final File codePath;
5423 final String codePathString;
5424 final File resourcePath;
5425 final String resourcePathString;
5426 private long timeStamp;
5427 private String timeStampString = "0";
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005428 final int versionCode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005429
5430 PackageSignatures signatures = new PackageSignatures();
5431
5432 boolean permissionsFixed;
5433
5434 /* Explicitly disabled components */
5435 HashSet<String> disabledComponents = new HashSet<String>(0);
5436 /* Explicitly enabled components */
5437 HashSet<String> enabledComponents = new HashSet<String>(0);
5438 int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
5439 int installStatus = PKG_INSTALL_COMPLETE;
Jacek Surazskic64322c2009-04-28 15:26:38 +02005440
5441 /* package name of the app that installed this package */
5442 String installerPackageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005443
5444 PackageSettingBase(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005445 int pVersionCode, int pkgFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005446 super(pkgFlags);
5447 this.name = name;
5448 this.codePath = codePath;
5449 this.codePathString = codePath.toString();
5450 this.resourcePath = resourcePath;
5451 this.resourcePathString = resourcePath.toString();
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005452 this.versionCode = pVersionCode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005453 }
5454
Jacek Surazskic64322c2009-04-28 15:26:38 +02005455 public void setInstallerPackageName(String packageName) {
5456 installerPackageName = packageName;
5457 }
5458
5459 String getInstallerPackageName() {
5460 return installerPackageName;
5461 }
5462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005463 public void setInstallStatus(int newStatus) {
5464 installStatus = newStatus;
5465 }
5466
5467 public int getInstallStatus() {
5468 return installStatus;
5469 }
5470
5471 public void setTimeStamp(long newStamp) {
5472 if (newStamp != timeStamp) {
5473 timeStamp = newStamp;
5474 timeStampString = Long.toString(newStamp);
5475 }
5476 }
5477
5478 public void setTimeStamp(long newStamp, String newStampStr) {
5479 timeStamp = newStamp;
5480 timeStampString = newStampStr;
5481 }
5482
5483 public long getTimeStamp() {
5484 return timeStamp;
5485 }
5486
5487 public String getTimeStampStr() {
5488 return timeStampString;
5489 }
5490
5491 public void copyFrom(PackageSettingBase base) {
5492 grantedPermissions = base.grantedPermissions;
5493 gids = base.gids;
5494 loadedPermissions = base.loadedPermissions;
5495
5496 timeStamp = base.timeStamp;
5497 timeStampString = base.timeStampString;
5498 signatures = base.signatures;
5499 permissionsFixed = base.permissionsFixed;
5500 disabledComponents = base.disabledComponents;
5501 enabledComponents = base.enabledComponents;
5502 enabled = base.enabled;
5503 installStatus = base.installStatus;
5504 }
5505
5506 void enableComponentLP(String componentClassName) {
5507 disabledComponents.remove(componentClassName);
5508 enabledComponents.add(componentClassName);
5509 }
5510
5511 void disableComponentLP(String componentClassName) {
5512 enabledComponents.remove(componentClassName);
5513 disabledComponents.add(componentClassName);
5514 }
5515
5516 void restoreComponentLP(String componentClassName) {
5517 enabledComponents.remove(componentClassName);
5518 disabledComponents.remove(componentClassName);
5519 }
5520
5521 int currentEnabledStateLP(String componentName) {
5522 if (enabledComponents.contains(componentName)) {
5523 return COMPONENT_ENABLED_STATE_ENABLED;
5524 } else if (disabledComponents.contains(componentName)) {
5525 return COMPONENT_ENABLED_STATE_DISABLED;
5526 } else {
5527 return COMPONENT_ENABLED_STATE_DEFAULT;
5528 }
5529 }
5530 }
5531
5532 /**
5533 * Settings data for a particular package we know about.
5534 */
5535 static final class PackageSetting extends PackageSettingBase {
5536 int userId;
5537 PackageParser.Package pkg;
5538 SharedUserSetting sharedUser;
5539
5540 PackageSetting(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005541 int pVersionCode, int pkgFlags) {
5542 super(name, codePath, resourcePath, pVersionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005543 }
5544
5545 @Override
5546 public String toString() {
5547 return "PackageSetting{"
5548 + Integer.toHexString(System.identityHashCode(this))
5549 + " " + name + "/" + userId + "}";
5550 }
5551 }
5552
5553 /**
5554 * Settings data for a particular shared user ID we know about.
5555 */
5556 static final class SharedUserSetting extends GrantedPermissions {
5557 final String name;
5558 int userId;
5559 final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
5560 final PackageSignatures signatures = new PackageSignatures();
5561
5562 SharedUserSetting(String _name, int _pkgFlags) {
5563 super(_pkgFlags);
5564 name = _name;
5565 }
5566
5567 @Override
5568 public String toString() {
5569 return "SharedUserSetting{"
5570 + Integer.toHexString(System.identityHashCode(this))
5571 + " " + name + "/" + userId + "}";
5572 }
5573 }
5574
5575 /**
5576 * Holds information about dynamic settings.
5577 */
5578 private static final class Settings {
5579 private final File mSettingsFilename;
5580 private final File mBackupSettingsFilename;
5581 private final HashMap<String, PackageSetting> mPackages =
5582 new HashMap<String, PackageSetting>();
5583 // The user's preferred packages/applications, in order of preference.
5584 // First is the most preferred.
5585 private final ArrayList<PackageSetting> mPreferredPackages =
5586 new ArrayList<PackageSetting>();
5587 // List of replaced system applications
5588 final HashMap<String, PackageSetting> mDisabledSysPackages =
5589 new HashMap<String, PackageSetting>();
5590
5591 // The user's preferred activities associated with particular intent
5592 // filters.
5593 private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
5594 new IntentResolver<PreferredActivity, PreferredActivity>() {
5595 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005596 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005597 PreferredActivity filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005598 out.print(prefix); out.print(
5599 Integer.toHexString(System.identityHashCode(filter)));
5600 out.print(' ');
5601 out.print(filter.mActivity.flattenToShortString());
5602 out.print(" match=0x");
5603 out.println( Integer.toHexString(filter.mMatch));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005604 if (filter.mSetComponents != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005605 out.print(prefix); out.println(" Selected from:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005606 for (int i=0; i<filter.mSetComponents.length; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005607 out.print(prefix); out.print(" ");
5608 out.println(filter.mSetComponents[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005609 }
5610 }
5611 }
5612 };
5613 private final HashMap<String, SharedUserSetting> mSharedUsers =
5614 new HashMap<String, SharedUserSetting>();
5615 private final ArrayList<Object> mUserIds = new ArrayList<Object>();
5616 private final SparseArray<Object> mOtherUserIds =
5617 new SparseArray<Object>();
5618
5619 // For reading/writing settings file.
5620 private final ArrayList<Signature> mPastSignatures =
5621 new ArrayList<Signature>();
5622
5623 // Mapping from permission names to info about them.
5624 final HashMap<String, BasePermission> mPermissions =
5625 new HashMap<String, BasePermission>();
5626
5627 // Mapping from permission tree names to info about them.
5628 final HashMap<String, BasePermission> mPermissionTrees =
5629 new HashMap<String, BasePermission>();
5630
5631 private final ArrayList<String> mPendingPreferredPackages
5632 = new ArrayList<String>();
5633
5634 private final StringBuilder mReadMessages = new StringBuilder();
5635
5636 private static final class PendingPackage extends PackageSettingBase {
5637 final int sharedId;
5638
5639 PendingPackage(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005640 int sharedId, int pVersionCode, int pkgFlags) {
5641 super(name, codePath, resourcePath, pVersionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005642 this.sharedId = sharedId;
5643 }
5644 }
5645 private final ArrayList<PendingPackage> mPendingPackages
5646 = new ArrayList<PendingPackage>();
5647
5648 Settings() {
5649 File dataDir = Environment.getDataDirectory();
5650 File systemDir = new File(dataDir, "system");
5651 systemDir.mkdirs();
5652 FileUtils.setPermissions(systemDir.toString(),
5653 FileUtils.S_IRWXU|FileUtils.S_IRWXG
5654 |FileUtils.S_IROTH|FileUtils.S_IXOTH,
5655 -1, -1);
5656 mSettingsFilename = new File(systemDir, "packages.xml");
5657 mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
5658 }
5659
5660 PackageSetting getPackageLP(PackageParser.Package pkg,
5661 SharedUserSetting sharedUser, File codePath, File resourcePath,
5662 int pkgFlags, boolean create, boolean add) {
5663 final String name = pkg.packageName;
5664 PackageSetting p = getPackageLP(name, sharedUser, codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005665 resourcePath, pkg.mVersionCode, pkgFlags, create, add);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005666
5667 if (p != null) {
5668 p.pkg = pkg;
5669 }
5670 return p;
5671 }
5672
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005673 PackageSetting peekPackageLP(String name) {
5674 return mPackages.get(name);
5675 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005676 PackageSetting p = mPackages.get(name);
5677 if (p != null && p.codePath.getPath().equals(codePath)) {
5678 return p;
5679 }
5680 return null;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005681 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005682 }
5683
5684 void setInstallStatus(String pkgName, int status) {
5685 PackageSetting p = mPackages.get(pkgName);
5686 if(p != null) {
5687 if(p.getInstallStatus() != status) {
5688 p.setInstallStatus(status);
5689 }
5690 }
5691 }
5692
Jacek Surazskic64322c2009-04-28 15:26:38 +02005693 void setInstallerPackageName(String pkgName,
5694 String installerPkgName) {
5695 PackageSetting p = mPackages.get(pkgName);
5696 if(p != null) {
5697 p.setInstallerPackageName(installerPkgName);
5698 }
5699 }
5700
5701 String getInstallerPackageName(String pkgName) {
5702 PackageSetting p = mPackages.get(pkgName);
5703 return (p == null) ? null : p.getInstallerPackageName();
5704 }
5705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005706 int getInstallStatus(String pkgName) {
5707 PackageSetting p = mPackages.get(pkgName);
5708 if(p != null) {
5709 return p.getInstallStatus();
5710 }
5711 return -1;
5712 }
5713
5714 SharedUserSetting getSharedUserLP(String name,
5715 int pkgFlags, boolean create) {
5716 SharedUserSetting s = mSharedUsers.get(name);
5717 if (s == null) {
5718 if (!create) {
5719 return null;
5720 }
5721 s = new SharedUserSetting(name, pkgFlags);
5722 if (MULTIPLE_APPLICATION_UIDS) {
5723 s.userId = newUserIdLP(s);
5724 } else {
5725 s.userId = FIRST_APPLICATION_UID;
5726 }
5727 Log.i(TAG, "New shared user " + name + ": id=" + s.userId);
5728 // < 0 means we couldn't assign a userid; fall out and return
5729 // s, which is currently null
5730 if (s.userId >= 0) {
5731 mSharedUsers.put(name, s);
5732 }
5733 }
5734
5735 return s;
5736 }
5737
5738 int disableSystemPackageLP(String name) {
5739 PackageSetting p = mPackages.get(name);
5740 if(p == null) {
5741 Log.w(TAG, "Package:"+name+" is not an installed package");
5742 return -1;
5743 }
5744 PackageSetting dp = mDisabledSysPackages.get(name);
5745 // always make sure the system package code and resource paths dont change
5746 if(dp == null) {
5747 if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
5748 p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
5749 }
5750 mDisabledSysPackages.put(name, p);
5751 }
5752 return removePackageLP(name);
5753 }
5754
5755 PackageSetting enableSystemPackageLP(String name) {
5756 PackageSetting p = mDisabledSysPackages.get(name);
5757 if(p == null) {
5758 Log.w(TAG, "Package:"+name+" is not disabled");
5759 return null;
5760 }
5761 // Reset flag in ApplicationInfo object
5762 if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
5763 p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
5764 }
5765 PackageSetting ret = addPackageLP(name, p.codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005766 p.resourcePath, p.userId, p.versionCode, p.pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005767 mDisabledSysPackages.remove(name);
5768 return ret;
5769 }
5770
5771 PackageSetting addPackageLP(String name, File codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005772 File resourcePath, int uid, int vc, int pkgFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005773 PackageSetting p = mPackages.get(name);
5774 if (p != null) {
5775 if (p.userId == uid) {
5776 return p;
5777 }
5778 reportSettingsProblem(Log.ERROR,
5779 "Adding duplicate package, keeping first: " + name);
5780 return null;
5781 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005782 p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005783 p.userId = uid;
5784 if (addUserIdLP(uid, p, name)) {
5785 mPackages.put(name, p);
5786 return p;
5787 }
5788 return null;
5789 }
5790
5791 SharedUserSetting addSharedUserLP(String name, int uid, int pkgFlags) {
5792 SharedUserSetting s = mSharedUsers.get(name);
5793 if (s != null) {
5794 if (s.userId == uid) {
5795 return s;
5796 }
5797 reportSettingsProblem(Log.ERROR,
5798 "Adding duplicate shared user, keeping first: " + name);
5799 return null;
5800 }
5801 s = new SharedUserSetting(name, pkgFlags);
5802 s.userId = uid;
5803 if (addUserIdLP(uid, s, name)) {
5804 mSharedUsers.put(name, s);
5805 return s;
5806 }
5807 return null;
5808 }
5809
5810 private PackageSetting getPackageLP(String name,
5811 SharedUserSetting sharedUser, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005812 int vc, int pkgFlags, boolean create, boolean add) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005813 PackageSetting p = mPackages.get(name);
5814 if (p != null) {
5815 if (!p.codePath.equals(codePath)) {
5816 // Check to see if its a disabled system app
5817 PackageSetting ps = mDisabledSysPackages.get(name);
5818 if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
5819 // Could be a replaced system package
5820 // Note that if the user replaced a system app, the user has to physically
5821 // delete the new one in order to revert to the system app. So even
5822 // if the user updated the system app via an update, the user still
5823 // has to delete the one installed in the data partition in order to pick up the
5824 // new system package.
5825 return p;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07005826 } else if ((p.pkg != null) && (p.pkg.applicationInfo != null) &&
5827 ((p.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
5828 // Check for non-system apps
5829 reportSettingsProblem(Log.WARN,
5830 "Package " + name + " codePath changed from " + p.codePath
5831 + " to " + codePath + "; Retaining data and using new code");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005832 } else {
5833 reportSettingsProblem(Log.WARN,
5834 "Package " + name + " codePath changed from " + p.codePath
5835 + " to " + codePath + "; replacing with new");
5836 p = null;
5837 }
5838 } else if (p.sharedUser != sharedUser) {
5839 reportSettingsProblem(Log.WARN,
5840 "Package " + name + " shared user changed from "
5841 + (p.sharedUser != null ? p.sharedUser.name : "<nothing>")
5842 + " to "
5843 + (sharedUser != null ? sharedUser.name : "<nothing>")
5844 + "; replacing with new");
5845 p = null;
5846 }
5847 }
5848 if (p == null) {
5849 // Create a new PackageSettings entry. this can end up here because
5850 // of code path mismatch or user id mismatch of an updated system partition
5851 if (!create) {
5852 return null;
5853 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005854 p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005855 p.setTimeStamp(codePath.lastModified());
Dianne Hackborn5d6d7732009-05-13 18:09:56 -07005856 p.sharedUser = sharedUser;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005857 if (sharedUser != null) {
5858 p.userId = sharedUser.userId;
5859 } else if (MULTIPLE_APPLICATION_UIDS) {
5860 p.userId = newUserIdLP(p);
5861 } else {
5862 p.userId = FIRST_APPLICATION_UID;
5863 }
5864 if (p.userId < 0) {
5865 reportSettingsProblem(Log.WARN,
5866 "Package " + name + " could not be assigned a valid uid");
5867 return null;
5868 }
5869 if (add) {
5870 // Finish adding new package by adding it and updating shared
5871 // user preferences
5872 insertPackageSettingLP(p, name, sharedUser);
5873 }
5874 }
5875 return p;
5876 }
5877
5878 // Utility method that adds a PackageSetting to mPackages and
5879 // completes updating the shared user attributes
5880 private void insertPackageSettingLP(PackageSetting p, String name,
5881 SharedUserSetting sharedUser) {
5882 mPackages.put(name, p);
5883 if (sharedUser != null) {
5884 if (p.sharedUser != null && p.sharedUser != sharedUser) {
5885 reportSettingsProblem(Log.ERROR,
5886 "Package " + p.name + " was user "
5887 + p.sharedUser + " but is now " + sharedUser
5888 + "; I am not changing its files so it will probably fail!");
5889 p.sharedUser.packages.remove(p);
5890 } else if (p.userId != sharedUser.userId) {
5891 reportSettingsProblem(Log.ERROR,
5892 "Package " + p.name + " was user id " + p.userId
5893 + " but is now user " + sharedUser
5894 + " with id " + sharedUser.userId
5895 + "; I am not changing its files so it will probably fail!");
5896 }
5897
5898 sharedUser.packages.add(p);
5899 p.sharedUser = sharedUser;
5900 p.userId = sharedUser.userId;
5901 }
5902 }
5903
5904 private void updateSharedUserPerms (PackageSetting deletedPs) {
5905 if ( (deletedPs == null) || (deletedPs.pkg == null)) {
5906 Log.i(TAG, "Trying to update info for null package. Just ignoring");
5907 return;
5908 }
5909 // No sharedUserId
5910 if (deletedPs.sharedUser == null) {
5911 return;
5912 }
5913 SharedUserSetting sus = deletedPs.sharedUser;
5914 // Update permissions
5915 for (String eachPerm: deletedPs.pkg.requestedPermissions) {
5916 boolean used = false;
5917 if (!sus.grantedPermissions.contains (eachPerm)) {
5918 continue;
5919 }
5920 for (PackageSetting pkg:sus.packages) {
5921 if (pkg.grantedPermissions.contains (eachPerm)) {
5922 used = true;
5923 break;
5924 }
5925 }
5926 if (!used) {
5927 // can safely delete this permission from list
5928 sus.grantedPermissions.remove(eachPerm);
5929 sus.loadedPermissions.remove(eachPerm);
5930 }
5931 }
5932 // Update gids
5933 int newGids[] = null;
5934 for (PackageSetting pkg:sus.packages) {
5935 newGids = appendInts(newGids, pkg.gids);
5936 }
5937 sus.gids = newGids;
5938 }
5939
5940 private int removePackageLP(String name) {
5941 PackageSetting p = mPackages.get(name);
5942 if (p != null) {
5943 mPackages.remove(name);
5944 if (p.sharedUser != null) {
5945 p.sharedUser.packages.remove(p);
5946 if (p.sharedUser.packages.size() == 0) {
5947 mSharedUsers.remove(p.sharedUser.name);
5948 removeUserIdLP(p.sharedUser.userId);
5949 return p.sharedUser.userId;
5950 }
5951 } else {
5952 removeUserIdLP(p.userId);
5953 return p.userId;
5954 }
5955 }
5956 return -1;
5957 }
5958
5959 private boolean addUserIdLP(int uid, Object obj, Object name) {
5960 if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) {
5961 return false;
5962 }
5963
5964 if (uid >= FIRST_APPLICATION_UID) {
5965 int N = mUserIds.size();
5966 final int index = uid - FIRST_APPLICATION_UID;
5967 while (index >= N) {
5968 mUserIds.add(null);
5969 N++;
5970 }
5971 if (mUserIds.get(index) != null) {
5972 reportSettingsProblem(Log.ERROR,
5973 "Adding duplicate shared id: " + uid
5974 + " name=" + name);
5975 return false;
5976 }
5977 mUserIds.set(index, obj);
5978 } else {
5979 if (mOtherUserIds.get(uid) != null) {
5980 reportSettingsProblem(Log.ERROR,
5981 "Adding duplicate shared id: " + uid
5982 + " name=" + name);
5983 return false;
5984 }
5985 mOtherUserIds.put(uid, obj);
5986 }
5987 return true;
5988 }
5989
5990 public Object getUserIdLP(int uid) {
5991 if (uid >= FIRST_APPLICATION_UID) {
5992 int N = mUserIds.size();
5993 final int index = uid - FIRST_APPLICATION_UID;
5994 return index < N ? mUserIds.get(index) : null;
5995 } else {
5996 return mOtherUserIds.get(uid);
5997 }
5998 }
5999
6000 private void removeUserIdLP(int uid) {
6001 if (uid >= FIRST_APPLICATION_UID) {
6002 int N = mUserIds.size();
6003 final int index = uid - FIRST_APPLICATION_UID;
6004 if (index < N) mUserIds.set(index, null);
6005 } else {
6006 mOtherUserIds.remove(uid);
6007 }
6008 }
6009
6010 void writeLP() {
6011 //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
6012
6013 // Keep the old settings around until we know the new ones have
6014 // been successfully written.
6015 if (mSettingsFilename.exists()) {
6016 if (mBackupSettingsFilename.exists()) {
6017 mBackupSettingsFilename.delete();
6018 }
6019 mSettingsFilename.renameTo(mBackupSettingsFilename);
6020 }
6021
6022 mPastSignatures.clear();
6023
6024 try {
6025 FileOutputStream str = new FileOutputStream(mSettingsFilename);
6026
6027 //XmlSerializer serializer = XmlUtils.serializerInstance();
6028 XmlSerializer serializer = new FastXmlSerializer();
6029 serializer.setOutput(str, "utf-8");
6030 serializer.startDocument(null, true);
6031 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
6032
6033 serializer.startTag(null, "packages");
6034
6035 serializer.startTag(null, "permission-trees");
6036 for (BasePermission bp : mPermissionTrees.values()) {
6037 writePermission(serializer, bp);
6038 }
6039 serializer.endTag(null, "permission-trees");
6040
6041 serializer.startTag(null, "permissions");
6042 for (BasePermission bp : mPermissions.values()) {
6043 writePermission(serializer, bp);
6044 }
6045 serializer.endTag(null, "permissions");
6046
6047 for (PackageSetting pkg : mPackages.values()) {
6048 writePackage(serializer, pkg);
6049 }
6050
6051 for (PackageSetting pkg : mDisabledSysPackages.values()) {
6052 writeDisabledSysPackage(serializer, pkg);
6053 }
6054
6055 serializer.startTag(null, "preferred-packages");
6056 int N = mPreferredPackages.size();
6057 for (int i=0; i<N; i++) {
6058 PackageSetting pkg = mPreferredPackages.get(i);
6059 serializer.startTag(null, "item");
6060 serializer.attribute(null, "name", pkg.name);
6061 serializer.endTag(null, "item");
6062 }
6063 serializer.endTag(null, "preferred-packages");
6064
6065 serializer.startTag(null, "preferred-activities");
6066 for (PreferredActivity pa : mPreferredActivities.filterSet()) {
6067 serializer.startTag(null, "item");
6068 pa.writeToXml(serializer);
6069 serializer.endTag(null, "item");
6070 }
6071 serializer.endTag(null, "preferred-activities");
6072
6073 for (SharedUserSetting usr : mSharedUsers.values()) {
6074 serializer.startTag(null, "shared-user");
6075 serializer.attribute(null, "name", usr.name);
6076 serializer.attribute(null, "userId",
6077 Integer.toString(usr.userId));
6078 usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
6079 serializer.startTag(null, "perms");
6080 for (String name : usr.grantedPermissions) {
6081 serializer.startTag(null, "item");
6082 serializer.attribute(null, "name", name);
6083 serializer.endTag(null, "item");
6084 }
6085 serializer.endTag(null, "perms");
6086 serializer.endTag(null, "shared-user");
6087 }
6088
6089 serializer.endTag(null, "packages");
6090
6091 serializer.endDocument();
6092
6093 str.flush();
6094 str.close();
6095
6096 // New settings successfully written, old ones are no longer
6097 // needed.
6098 mBackupSettingsFilename.delete();
6099 FileUtils.setPermissions(mSettingsFilename.toString(),
6100 FileUtils.S_IRUSR|FileUtils.S_IWUSR
6101 |FileUtils.S_IRGRP|FileUtils.S_IWGRP
6102 |FileUtils.S_IROTH,
6103 -1, -1);
6104
6105 } catch(XmlPullParserException e) {
6106 Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
6107
6108 } catch(java.io.IOException e) {
6109 Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
6110
6111 }
6112
6113 //Debug.stopMethodTracing();
6114 }
6115
6116 void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
6117 throws java.io.IOException {
6118 serializer.startTag(null, "updated-package");
6119 serializer.attribute(null, "name", pkg.name);
6120 serializer.attribute(null, "codePath", pkg.codePathString);
6121 serializer.attribute(null, "ts", pkg.getTimeStampStr());
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006122 serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006123 if (!pkg.resourcePathString.equals(pkg.codePathString)) {
6124 serializer.attribute(null, "resourcePath", pkg.resourcePathString);
6125 }
6126 if (pkg.sharedUser == null) {
6127 serializer.attribute(null, "userId",
6128 Integer.toString(pkg.userId));
6129 } else {
6130 serializer.attribute(null, "sharedUserId",
6131 Integer.toString(pkg.userId));
6132 }
6133 serializer.startTag(null, "perms");
6134 if (pkg.sharedUser == null) {
6135 // If this is a shared user, the permissions will
6136 // be written there. We still need to write an
6137 // empty permissions list so permissionsFixed will
6138 // be set.
6139 for (final String name : pkg.grantedPermissions) {
6140 BasePermission bp = mPermissions.get(name);
6141 if ((bp != null) && (bp.perm != null) && (bp.perm.info != null)) {
6142 // We only need to write signature or system permissions but this wont
6143 // match the semantics of grantedPermissions. So write all permissions.
6144 serializer.startTag(null, "item");
6145 serializer.attribute(null, "name", name);
6146 serializer.endTag(null, "item");
6147 }
6148 }
6149 }
6150 serializer.endTag(null, "perms");
6151 serializer.endTag(null, "updated-package");
6152 }
6153
6154 void writePackage(XmlSerializer serializer, final PackageSetting pkg)
6155 throws java.io.IOException {
6156 serializer.startTag(null, "package");
6157 serializer.attribute(null, "name", pkg.name);
6158 serializer.attribute(null, "codePath", pkg.codePathString);
6159 if (!pkg.resourcePathString.equals(pkg.codePathString)) {
6160 serializer.attribute(null, "resourcePath", pkg.resourcePathString);
6161 }
6162 serializer.attribute(null, "system",
6163 (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
6164 ? "true" : "false");
6165 serializer.attribute(null, "ts", pkg.getTimeStampStr());
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006166 serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006167 if (pkg.sharedUser == null) {
6168 serializer.attribute(null, "userId",
6169 Integer.toString(pkg.userId));
6170 } else {
6171 serializer.attribute(null, "sharedUserId",
6172 Integer.toString(pkg.userId));
6173 }
6174 if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
6175 serializer.attribute(null, "enabled",
6176 pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
6177 ? "true" : "false");
6178 }
6179 if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
6180 serializer.attribute(null, "installStatus", "false");
6181 }
Jacek Surazskic64322c2009-04-28 15:26:38 +02006182 if (pkg.installerPackageName != null) {
6183 serializer.attribute(null, "installer", pkg.installerPackageName);
6184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006185 pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
6186 if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
6187 serializer.startTag(null, "perms");
6188 if (pkg.sharedUser == null) {
6189 // If this is a shared user, the permissions will
6190 // be written there. We still need to write an
6191 // empty permissions list so permissionsFixed will
6192 // be set.
6193 for (final String name : pkg.grantedPermissions) {
6194 serializer.startTag(null, "item");
6195 serializer.attribute(null, "name", name);
6196 serializer.endTag(null, "item");
6197 }
6198 }
6199 serializer.endTag(null, "perms");
6200 }
6201 if (pkg.disabledComponents.size() > 0) {
6202 serializer.startTag(null, "disabled-components");
6203 for (final String name : pkg.disabledComponents) {
6204 serializer.startTag(null, "item");
6205 serializer.attribute(null, "name", name);
6206 serializer.endTag(null, "item");
6207 }
6208 serializer.endTag(null, "disabled-components");
6209 }
6210 if (pkg.enabledComponents.size() > 0) {
6211 serializer.startTag(null, "enabled-components");
6212 for (final String name : pkg.enabledComponents) {
6213 serializer.startTag(null, "item");
6214 serializer.attribute(null, "name", name);
6215 serializer.endTag(null, "item");
6216 }
6217 serializer.endTag(null, "enabled-components");
6218 }
Jacek Surazskic64322c2009-04-28 15:26:38 +02006219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006220 serializer.endTag(null, "package");
6221 }
6222
6223 void writePermission(XmlSerializer serializer, BasePermission bp)
6224 throws XmlPullParserException, java.io.IOException {
6225 if (bp.type != BasePermission.TYPE_BUILTIN
6226 && bp.sourcePackage != null) {
6227 serializer.startTag(null, "item");
6228 serializer.attribute(null, "name", bp.name);
6229 serializer.attribute(null, "package", bp.sourcePackage);
6230 if (DEBUG_SETTINGS) Log.v(TAG,
6231 "Writing perm: name=" + bp.name + " type=" + bp.type);
6232 if (bp.type == BasePermission.TYPE_DYNAMIC) {
6233 PermissionInfo pi = bp.perm != null ? bp.perm.info
6234 : bp.pendingInfo;
6235 if (pi != null) {
6236 serializer.attribute(null, "type", "dynamic");
6237 if (pi.icon != 0) {
6238 serializer.attribute(null, "icon",
6239 Integer.toString(pi.icon));
6240 }
6241 if (pi.nonLocalizedLabel != null) {
6242 serializer.attribute(null, "label",
6243 pi.nonLocalizedLabel.toString());
6244 }
6245 if (pi.protectionLevel !=
6246 PermissionInfo.PROTECTION_NORMAL) {
6247 serializer.attribute(null, "protection",
6248 Integer.toString(pi.protectionLevel));
6249 }
6250 }
6251 }
6252 serializer.endTag(null, "item");
6253 }
6254 }
6255
6256 String getReadMessagesLP() {
6257 return mReadMessages.toString();
6258 }
6259
6260 ArrayList<String> getListOfIncompleteInstallPackages() {
6261 HashSet<String> kList = new HashSet<String>(mPackages.keySet());
6262 Iterator<String> its = kList.iterator();
6263 ArrayList<String> ret = new ArrayList<String>();
6264 while(its.hasNext()) {
6265 String key = its.next();
6266 PackageSetting ps = mPackages.get(key);
6267 if(ps.getInstallStatus() == PKG_INSTALL_INCOMPLETE) {
6268 ret.add(key);
6269 }
6270 }
6271 return ret;
6272 }
6273
6274 boolean readLP() {
6275 FileInputStream str = null;
6276 if (mBackupSettingsFilename.exists()) {
6277 try {
6278 str = new FileInputStream(mBackupSettingsFilename);
6279 mReadMessages.append("Reading from backup settings file\n");
6280 Log.i(TAG, "Reading from backup settings file!");
6281 } catch (java.io.IOException e) {
6282 // We'll try for the normal settings file.
6283 }
6284 }
6285
6286 mPastSignatures.clear();
6287
6288 try {
6289 if (str == null) {
6290 if (!mSettingsFilename.exists()) {
6291 mReadMessages.append("No settings file found\n");
6292 Log.i(TAG, "No current settings file!");
6293 return false;
6294 }
6295 str = new FileInputStream(mSettingsFilename);
6296 }
6297 XmlPullParser parser = Xml.newPullParser();
6298 parser.setInput(str, null);
6299
6300 int type;
6301 while ((type=parser.next()) != XmlPullParser.START_TAG
6302 && type != XmlPullParser.END_DOCUMENT) {
6303 ;
6304 }
6305
6306 if (type != XmlPullParser.START_TAG) {
6307 mReadMessages.append("No start tag found in settings file\n");
6308 Log.e(TAG, "No start tag found in package manager settings");
6309 return false;
6310 }
6311
6312 int outerDepth = parser.getDepth();
6313 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6314 && (type != XmlPullParser.END_TAG
6315 || parser.getDepth() > outerDepth)) {
6316 if (type == XmlPullParser.END_TAG
6317 || type == XmlPullParser.TEXT) {
6318 continue;
6319 }
6320
6321 String tagName = parser.getName();
6322 if (tagName.equals("package")) {
6323 readPackageLP(parser);
6324 } else if (tagName.equals("permissions")) {
6325 readPermissionsLP(mPermissions, parser);
6326 } else if (tagName.equals("permission-trees")) {
6327 readPermissionsLP(mPermissionTrees, parser);
6328 } else if (tagName.equals("shared-user")) {
6329 readSharedUserLP(parser);
6330 } else if (tagName.equals("preferred-packages")) {
6331 readPreferredPackagesLP(parser);
6332 } else if (tagName.equals("preferred-activities")) {
6333 readPreferredActivitiesLP(parser);
6334 } else if(tagName.equals("updated-package")) {
6335 readDisabledSysPackageLP(parser);
6336 } else {
6337 Log.w(TAG, "Unknown element under <packages>: "
6338 + parser.getName());
6339 XmlUtils.skipCurrentTag(parser);
6340 }
6341 }
6342
6343 str.close();
6344
6345 } catch(XmlPullParserException e) {
6346 mReadMessages.append("Error reading: " + e.toString());
6347 Log.e(TAG, "Error reading package manager settings", e);
6348
6349 } catch(java.io.IOException e) {
6350 mReadMessages.append("Error reading: " + e.toString());
6351 Log.e(TAG, "Error reading package manager settings", e);
6352
6353 }
6354
6355 int N = mPendingPackages.size();
6356 for (int i=0; i<N; i++) {
6357 final PendingPackage pp = mPendingPackages.get(i);
6358 Object idObj = getUserIdLP(pp.sharedId);
6359 if (idObj != null && idObj instanceof SharedUserSetting) {
6360 PackageSetting p = getPackageLP(pp.name,
6361 (SharedUserSetting)idObj, pp.codePath, pp.resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006362 pp.versionCode, pp.pkgFlags, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006363 if (p == null) {
6364 Log.w(TAG, "Unable to create application package for "
6365 + pp.name);
6366 continue;
6367 }
6368 p.copyFrom(pp);
6369 } else if (idObj != null) {
6370 String msg = "Bad package setting: package " + pp.name
6371 + " has shared uid " + pp.sharedId
6372 + " that is not a shared uid\n";
6373 mReadMessages.append(msg);
6374 Log.e(TAG, msg);
6375 } else {
6376 String msg = "Bad package setting: package " + pp.name
6377 + " has shared uid " + pp.sharedId
6378 + " that is not defined\n";
6379 mReadMessages.append(msg);
6380 Log.e(TAG, msg);
6381 }
6382 }
6383 mPendingPackages.clear();
6384
6385 N = mPendingPreferredPackages.size();
6386 mPreferredPackages.clear();
6387 for (int i=0; i<N; i++) {
6388 final String name = mPendingPreferredPackages.get(i);
6389 final PackageSetting p = mPackages.get(name);
6390 if (p != null) {
6391 mPreferredPackages.add(p);
6392 } else {
6393 Log.w(TAG, "Unknown preferred package: " + name);
6394 }
6395 }
6396 mPendingPreferredPackages.clear();
6397
6398 mReadMessages.append("Read completed successfully: "
6399 + mPackages.size() + " packages, "
6400 + mSharedUsers.size() + " shared uids\n");
6401
6402 return true;
6403 }
6404
6405 private int readInt(XmlPullParser parser, String ns, String name,
6406 int defValue) {
6407 String v = parser.getAttributeValue(ns, name);
6408 try {
6409 if (v == null) {
6410 return defValue;
6411 }
6412 return Integer.parseInt(v);
6413 } catch (NumberFormatException e) {
6414 reportSettingsProblem(Log.WARN,
6415 "Error in package manager settings: attribute " +
6416 name + " has bad integer value " + v + " at "
6417 + parser.getPositionDescription());
6418 }
6419 return defValue;
6420 }
6421
6422 private void readPermissionsLP(HashMap<String, BasePermission> out,
6423 XmlPullParser parser)
6424 throws IOException, XmlPullParserException {
6425 int outerDepth = parser.getDepth();
6426 int type;
6427 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6428 && (type != XmlPullParser.END_TAG
6429 || parser.getDepth() > outerDepth)) {
6430 if (type == XmlPullParser.END_TAG
6431 || type == XmlPullParser.TEXT) {
6432 continue;
6433 }
6434
6435 String tagName = parser.getName();
6436 if (tagName.equals("item")) {
6437 String name = parser.getAttributeValue(null, "name");
6438 String sourcePackage = parser.getAttributeValue(null, "package");
6439 String ptype = parser.getAttributeValue(null, "type");
6440 if (name != null && sourcePackage != null) {
6441 boolean dynamic = "dynamic".equals(ptype);
6442 BasePermission bp = new BasePermission(name, sourcePackage,
6443 dynamic
6444 ? BasePermission.TYPE_DYNAMIC
6445 : BasePermission.TYPE_NORMAL);
6446 if (dynamic) {
6447 PermissionInfo pi = new PermissionInfo();
6448 pi.packageName = sourcePackage.intern();
6449 pi.name = name.intern();
6450 pi.icon = readInt(parser, null, "icon", 0);
6451 pi.nonLocalizedLabel = parser.getAttributeValue(
6452 null, "label");
6453 pi.protectionLevel = readInt(parser, null, "protection",
6454 PermissionInfo.PROTECTION_NORMAL);
6455 bp.pendingInfo = pi;
6456 }
6457 out.put(bp.name, bp);
6458 } else {
6459 reportSettingsProblem(Log.WARN,
6460 "Error in package manager settings: permissions has"
6461 + " no name at " + parser.getPositionDescription());
6462 }
6463 } else {
6464 reportSettingsProblem(Log.WARN,
6465 "Unknown element reading permissions: "
6466 + parser.getName() + " at "
6467 + parser.getPositionDescription());
6468 }
6469 XmlUtils.skipCurrentTag(parser);
6470 }
6471 }
6472
6473 private void readDisabledSysPackageLP(XmlPullParser parser)
6474 throws XmlPullParserException, IOException {
6475 String name = parser.getAttributeValue(null, "name");
6476 String codePathStr = parser.getAttributeValue(null, "codePath");
6477 String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
6478 if(resourcePathStr == null) {
6479 resourcePathStr = codePathStr;
6480 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006481 String version = parser.getAttributeValue(null, "version");
6482 int versionCode = 0;
6483 if (version != null) {
6484 try {
6485 versionCode = Integer.parseInt(version);
6486 } catch (NumberFormatException e) {
6487 }
6488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006489
6490 int pkgFlags = 0;
6491 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6492 PackageSetting ps = new PackageSetting(name,
6493 new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006494 new File(resourcePathStr), versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006495 String timeStampStr = parser.getAttributeValue(null, "ts");
6496 if (timeStampStr != null) {
6497 try {
6498 long timeStamp = Long.parseLong(timeStampStr);
6499 ps.setTimeStamp(timeStamp, timeStampStr);
6500 } catch (NumberFormatException e) {
6501 }
6502 }
6503 String idStr = parser.getAttributeValue(null, "userId");
6504 ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
6505 if(ps.userId <= 0) {
6506 String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
6507 ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
6508 }
6509 int outerDepth = parser.getDepth();
6510 int type;
6511 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6512 && (type != XmlPullParser.END_TAG
6513 || parser.getDepth() > outerDepth)) {
6514 if (type == XmlPullParser.END_TAG
6515 || type == XmlPullParser.TEXT) {
6516 continue;
6517 }
6518
6519 String tagName = parser.getName();
6520 if (tagName.equals("perms")) {
6521 readGrantedPermissionsLP(parser,
6522 ps.grantedPermissions);
6523 } else {
6524 reportSettingsProblem(Log.WARN,
6525 "Unknown element under <updated-package>: "
6526 + parser.getName());
6527 XmlUtils.skipCurrentTag(parser);
6528 }
6529 }
6530 mDisabledSysPackages.put(name, ps);
6531 }
6532
6533 private void readPackageLP(XmlPullParser parser)
6534 throws XmlPullParserException, IOException {
6535 String name = null;
6536 String idStr = null;
6537 String sharedIdStr = null;
6538 String codePathStr = null;
6539 String resourcePathStr = null;
6540 String systemStr = null;
Jacek Surazskic64322c2009-04-28 15:26:38 +02006541 String installerPackageName = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006542 int pkgFlags = 0;
6543 String timeStampStr;
6544 long timeStamp = 0;
6545 PackageSettingBase packageSetting = null;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006546 String version = null;
6547 int versionCode = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006548 try {
6549 name = parser.getAttributeValue(null, "name");
6550 idStr = parser.getAttributeValue(null, "userId");
6551 sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
6552 codePathStr = parser.getAttributeValue(null, "codePath");
6553 resourcePathStr = parser.getAttributeValue(null, "resourcePath");
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006554 version = parser.getAttributeValue(null, "version");
6555 if (version != null) {
6556 try {
6557 versionCode = Integer.parseInt(version);
6558 } catch (NumberFormatException e) {
6559 }
6560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006561 systemStr = parser.getAttributeValue(null, "system");
Jacek Surazskic64322c2009-04-28 15:26:38 +02006562 installerPackageName = parser.getAttributeValue(null, "installer");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006563 if (systemStr != null) {
6564 if ("true".equals(systemStr)) {
6565 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6566 }
6567 } else {
6568 // Old settings that don't specify system... just treat
6569 // them as system, good enough.
6570 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6571 }
6572 timeStampStr = parser.getAttributeValue(null, "ts");
6573 if (timeStampStr != null) {
6574 try {
6575 timeStamp = Long.parseLong(timeStampStr);
6576 } catch (NumberFormatException e) {
6577 }
6578 }
6579 if (DEBUG_SETTINGS) Log.v(TAG, "Reading package: " + name
6580 + " userId=" + idStr + " sharedUserId=" + sharedIdStr);
6581 int userId = idStr != null ? Integer.parseInt(idStr) : 0;
6582 if (resourcePathStr == null) {
6583 resourcePathStr = codePathStr;
6584 }
6585 if (name == null) {
6586 reportSettingsProblem(Log.WARN,
6587 "Error in package manager settings: <package> has no name at "
6588 + parser.getPositionDescription());
6589 } else if (codePathStr == null) {
6590 reportSettingsProblem(Log.WARN,
6591 "Error in package manager settings: <package> has no codePath at "
6592 + parser.getPositionDescription());
6593 } else if (userId > 0) {
6594 packageSetting = addPackageLP(name.intern(), new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006595 new File(resourcePathStr), userId, versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006596 if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
6597 + ": userId=" + userId + " pkg=" + packageSetting);
6598 if (packageSetting == null) {
6599 reportSettingsProblem(Log.ERROR,
6600 "Failure adding uid " + userId
6601 + " while parsing settings at "
6602 + parser.getPositionDescription());
6603 } else {
6604 packageSetting.setTimeStamp(timeStamp, timeStampStr);
6605 }
6606 } else if (sharedIdStr != null) {
6607 userId = sharedIdStr != null
6608 ? Integer.parseInt(sharedIdStr) : 0;
6609 if (userId > 0) {
6610 packageSetting = new PendingPackage(name.intern(), new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006611 new File(resourcePathStr), userId, versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006612 packageSetting.setTimeStamp(timeStamp, timeStampStr);
6613 mPendingPackages.add((PendingPackage) packageSetting);
6614 if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
6615 + ": sharedUserId=" + userId + " pkg="
6616 + packageSetting);
6617 } else {
6618 reportSettingsProblem(Log.WARN,
6619 "Error in package manager settings: package "
6620 + name + " has bad sharedId " + sharedIdStr
6621 + " at " + parser.getPositionDescription());
6622 }
6623 } else {
6624 reportSettingsProblem(Log.WARN,
6625 "Error in package manager settings: package "
6626 + name + " has bad userId " + idStr + " at "
6627 + parser.getPositionDescription());
6628 }
6629 } catch (NumberFormatException e) {
6630 reportSettingsProblem(Log.WARN,
6631 "Error in package manager settings: package "
6632 + name + " has bad userId " + idStr + " at "
6633 + parser.getPositionDescription());
6634 }
6635 if (packageSetting != null) {
Jacek Surazskic64322c2009-04-28 15:26:38 +02006636 packageSetting.installerPackageName = installerPackageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006637 final String enabledStr = parser.getAttributeValue(null, "enabled");
6638 if (enabledStr != null) {
6639 if (enabledStr.equalsIgnoreCase("true")) {
6640 packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
6641 } else if (enabledStr.equalsIgnoreCase("false")) {
6642 packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
6643 } else if (enabledStr.equalsIgnoreCase("default")) {
6644 packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
6645 } else {
6646 reportSettingsProblem(Log.WARN,
6647 "Error in package manager settings: package "
6648 + name + " has bad enabled value: " + idStr
6649 + " at " + parser.getPositionDescription());
6650 }
6651 } else {
6652 packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
6653 }
6654 final String installStatusStr = parser.getAttributeValue(null, "installStatus");
6655 if (installStatusStr != null) {
6656 if (installStatusStr.equalsIgnoreCase("false")) {
6657 packageSetting.installStatus = PKG_INSTALL_INCOMPLETE;
6658 } else {
6659 packageSetting.installStatus = PKG_INSTALL_COMPLETE;
6660 }
6661 }
6662
6663 int outerDepth = parser.getDepth();
6664 int type;
6665 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6666 && (type != XmlPullParser.END_TAG
6667 || parser.getDepth() > outerDepth)) {
6668 if (type == XmlPullParser.END_TAG
6669 || type == XmlPullParser.TEXT) {
6670 continue;
6671 }
6672
6673 String tagName = parser.getName();
6674 if (tagName.equals("disabled-components")) {
6675 readDisabledComponentsLP(packageSetting, parser);
6676 } else if (tagName.equals("enabled-components")) {
6677 readEnabledComponentsLP(packageSetting, parser);
6678 } else if (tagName.equals("sigs")) {
6679 packageSetting.signatures.readXml(parser, mPastSignatures);
6680 } else if (tagName.equals("perms")) {
6681 readGrantedPermissionsLP(parser,
6682 packageSetting.loadedPermissions);
6683 packageSetting.permissionsFixed = true;
6684 } else {
6685 reportSettingsProblem(Log.WARN,
6686 "Unknown element under <package>: "
6687 + parser.getName());
6688 XmlUtils.skipCurrentTag(parser);
6689 }
6690 }
6691 } else {
6692 XmlUtils.skipCurrentTag(parser);
6693 }
6694 }
6695
6696 private void readDisabledComponentsLP(PackageSettingBase packageSetting,
6697 XmlPullParser parser)
6698 throws IOException, XmlPullParserException {
6699 int outerDepth = parser.getDepth();
6700 int type;
6701 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6702 && (type != XmlPullParser.END_TAG
6703 || parser.getDepth() > outerDepth)) {
6704 if (type == XmlPullParser.END_TAG
6705 || type == XmlPullParser.TEXT) {
6706 continue;
6707 }
6708
6709 String tagName = parser.getName();
6710 if (tagName.equals("item")) {
6711 String name = parser.getAttributeValue(null, "name");
6712 if (name != null) {
6713 packageSetting.disabledComponents.add(name.intern());
6714 } else {
6715 reportSettingsProblem(Log.WARN,
6716 "Error in package manager settings: <disabled-components> has"
6717 + " no name at " + parser.getPositionDescription());
6718 }
6719 } else {
6720 reportSettingsProblem(Log.WARN,
6721 "Unknown element under <disabled-components>: "
6722 + parser.getName());
6723 }
6724 XmlUtils.skipCurrentTag(parser);
6725 }
6726 }
6727
6728 private void readEnabledComponentsLP(PackageSettingBase packageSetting,
6729 XmlPullParser parser)
6730 throws IOException, XmlPullParserException {
6731 int outerDepth = parser.getDepth();
6732 int type;
6733 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6734 && (type != XmlPullParser.END_TAG
6735 || parser.getDepth() > outerDepth)) {
6736 if (type == XmlPullParser.END_TAG
6737 || type == XmlPullParser.TEXT) {
6738 continue;
6739 }
6740
6741 String tagName = parser.getName();
6742 if (tagName.equals("item")) {
6743 String name = parser.getAttributeValue(null, "name");
6744 if (name != null) {
6745 packageSetting.enabledComponents.add(name.intern());
6746 } else {
6747 reportSettingsProblem(Log.WARN,
6748 "Error in package manager settings: <enabled-components> has"
6749 + " no name at " + parser.getPositionDescription());
6750 }
6751 } else {
6752 reportSettingsProblem(Log.WARN,
6753 "Unknown element under <enabled-components>: "
6754 + parser.getName());
6755 }
6756 XmlUtils.skipCurrentTag(parser);
6757 }
6758 }
6759
6760 private void readSharedUserLP(XmlPullParser parser)
6761 throws XmlPullParserException, IOException {
6762 String name = null;
6763 String idStr = null;
6764 int pkgFlags = 0;
6765 SharedUserSetting su = null;
6766 try {
6767 name = parser.getAttributeValue(null, "name");
6768 idStr = parser.getAttributeValue(null, "userId");
6769 int userId = idStr != null ? Integer.parseInt(idStr) : 0;
6770 if ("true".equals(parser.getAttributeValue(null, "system"))) {
6771 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6772 }
6773 if (name == null) {
6774 reportSettingsProblem(Log.WARN,
6775 "Error in package manager settings: <shared-user> has no name at "
6776 + parser.getPositionDescription());
6777 } else if (userId == 0) {
6778 reportSettingsProblem(Log.WARN,
6779 "Error in package manager settings: shared-user "
6780 + name + " has bad userId " + idStr + " at "
6781 + parser.getPositionDescription());
6782 } else {
6783 if ((su=addSharedUserLP(name.intern(), userId, pkgFlags)) == null) {
6784 reportSettingsProblem(Log.ERROR,
6785 "Occurred while parsing settings at "
6786 + parser.getPositionDescription());
6787 }
6788 }
6789 } catch (NumberFormatException e) {
6790 reportSettingsProblem(Log.WARN,
6791 "Error in package manager settings: package "
6792 + name + " has bad userId " + idStr + " at "
6793 + parser.getPositionDescription());
6794 };
6795
6796 if (su != null) {
6797 int outerDepth = parser.getDepth();
6798 int type;
6799 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6800 && (type != XmlPullParser.END_TAG
6801 || parser.getDepth() > outerDepth)) {
6802 if (type == XmlPullParser.END_TAG
6803 || type == XmlPullParser.TEXT) {
6804 continue;
6805 }
6806
6807 String tagName = parser.getName();
6808 if (tagName.equals("sigs")) {
6809 su.signatures.readXml(parser, mPastSignatures);
6810 } else if (tagName.equals("perms")) {
6811 readGrantedPermissionsLP(parser, su.loadedPermissions);
6812 } else {
6813 reportSettingsProblem(Log.WARN,
6814 "Unknown element under <shared-user>: "
6815 + parser.getName());
6816 XmlUtils.skipCurrentTag(parser);
6817 }
6818 }
6819
6820 } else {
6821 XmlUtils.skipCurrentTag(parser);
6822 }
6823 }
6824
6825 private void readGrantedPermissionsLP(XmlPullParser parser,
6826 HashSet<String> outPerms) throws IOException, XmlPullParserException {
6827 int outerDepth = parser.getDepth();
6828 int type;
6829 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6830 && (type != XmlPullParser.END_TAG
6831 || parser.getDepth() > outerDepth)) {
6832 if (type == XmlPullParser.END_TAG
6833 || type == XmlPullParser.TEXT) {
6834 continue;
6835 }
6836
6837 String tagName = parser.getName();
6838 if (tagName.equals("item")) {
6839 String name = parser.getAttributeValue(null, "name");
6840 if (name != null) {
6841 outPerms.add(name.intern());
6842 } else {
6843 reportSettingsProblem(Log.WARN,
6844 "Error in package manager settings: <perms> has"
6845 + " no name at " + parser.getPositionDescription());
6846 }
6847 } else {
6848 reportSettingsProblem(Log.WARN,
6849 "Unknown element under <perms>: "
6850 + parser.getName());
6851 }
6852 XmlUtils.skipCurrentTag(parser);
6853 }
6854 }
6855
6856 private void readPreferredPackagesLP(XmlPullParser parser)
6857 throws XmlPullParserException, IOException {
6858 int outerDepth = parser.getDepth();
6859 int type;
6860 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6861 && (type != XmlPullParser.END_TAG
6862 || parser.getDepth() > outerDepth)) {
6863 if (type == XmlPullParser.END_TAG
6864 || type == XmlPullParser.TEXT) {
6865 continue;
6866 }
6867
6868 String tagName = parser.getName();
6869 if (tagName.equals("item")) {
6870 String name = parser.getAttributeValue(null, "name");
6871 if (name != null) {
6872 mPendingPreferredPackages.add(name);
6873 } else {
6874 reportSettingsProblem(Log.WARN,
6875 "Error in package manager settings: <preferred-package> has no name at "
6876 + parser.getPositionDescription());
6877 }
6878 } else {
6879 reportSettingsProblem(Log.WARN,
6880 "Unknown element under <preferred-packages>: "
6881 + parser.getName());
6882 }
6883 XmlUtils.skipCurrentTag(parser);
6884 }
6885 }
6886
6887 private void readPreferredActivitiesLP(XmlPullParser parser)
6888 throws XmlPullParserException, IOException {
6889 int outerDepth = parser.getDepth();
6890 int type;
6891 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6892 && (type != XmlPullParser.END_TAG
6893 || parser.getDepth() > outerDepth)) {
6894 if (type == XmlPullParser.END_TAG
6895 || type == XmlPullParser.TEXT) {
6896 continue;
6897 }
6898
6899 String tagName = parser.getName();
6900 if (tagName.equals("item")) {
6901 PreferredActivity pa = new PreferredActivity(parser);
6902 if (pa.mParseError == null) {
6903 mPreferredActivities.addFilter(pa);
6904 } else {
6905 reportSettingsProblem(Log.WARN,
6906 "Error in package manager settings: <preferred-activity> "
6907 + pa.mParseError + " at "
6908 + parser.getPositionDescription());
6909 }
6910 } else {
6911 reportSettingsProblem(Log.WARN,
6912 "Unknown element under <preferred-activities>: "
6913 + parser.getName());
6914 XmlUtils.skipCurrentTag(parser);
6915 }
6916 }
6917 }
6918
6919 // Returns -1 if we could not find an available UserId to assign
6920 private int newUserIdLP(Object obj) {
6921 // Let's be stupidly inefficient for now...
6922 final int N = mUserIds.size();
6923 for (int i=0; i<N; i++) {
6924 if (mUserIds.get(i) == null) {
6925 mUserIds.set(i, obj);
6926 return FIRST_APPLICATION_UID + i;
6927 }
6928 }
6929
6930 // None left?
6931 if (N >= MAX_APPLICATION_UIDS) {
6932 return -1;
6933 }
6934
6935 mUserIds.add(obj);
6936 return FIRST_APPLICATION_UID + N;
6937 }
6938
6939 public PackageSetting getDisabledSystemPkg(String name) {
6940 synchronized(mPackages) {
6941 PackageSetting ps = mDisabledSysPackages.get(name);
6942 return ps;
6943 }
6944 }
6945
6946 boolean isEnabledLP(ComponentInfo componentInfo, int flags) {
6947 final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
6948 if (Config.LOGV) {
6949 Log.v(TAG, "isEnabledLock - packageName = " + componentInfo.packageName
6950 + " componentName = " + componentInfo.name);
6951 Log.v(TAG, "enabledComponents: "
6952 + Arrays.toString(packageSettings.enabledComponents.toArray()));
6953 Log.v(TAG, "disabledComponents: "
6954 + Arrays.toString(packageSettings.disabledComponents.toArray()));
6955 }
6956 return ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0)
6957 || ((componentInfo.enabled
6958 && ((packageSettings.enabled == COMPONENT_ENABLED_STATE_ENABLED)
6959 || (componentInfo.applicationInfo.enabled
6960 && packageSettings.enabled != COMPONENT_ENABLED_STATE_DISABLED))
6961 && !packageSettings.disabledComponents.contains(componentInfo.name))
6962 || packageSettings.enabledComponents.contains(componentInfo.name));
6963 }
6964 }
6965}