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