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