blob: 238403c391433936ab89ae7a0a3b13f034353b1c [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
Suchi Amalapurapuc028be42010-01-25 12:19:12 -080019import com.android.internal.app.IMediaContainerService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import com.android.internal.app.ResolverActivity;
Tom Taylord4a47292009-12-21 13:59:18 -080021import com.android.common.FastXmlSerializer;
22import com.android.common.XmlUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
24import org.xmlpull.v1.XmlPullParser;
25import org.xmlpull.v1.XmlPullParserException;
26import org.xmlpull.v1.XmlSerializer;
27
28import android.app.ActivityManagerNative;
29import android.app.IActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.content.Context;
32import android.content.Intent;
33import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070034import android.content.IntentSender;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -080035import android.content.ServiceConnection;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070036import android.content.IntentSender.SendIntentException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.content.pm.ActivityInfo;
38import android.content.pm.ApplicationInfo;
39import android.content.pm.ComponentInfo;
Dianne Hackborn49237342009-08-27 20:08:01 -070040import android.content.pm.FeatureInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.content.pm.IPackageDataObserver;
42import android.content.pm.IPackageDeleteObserver;
43import android.content.pm.IPackageInstallObserver;
44import android.content.pm.IPackageManager;
45import android.content.pm.IPackageStatsObserver;
46import android.content.pm.InstrumentationInfo;
47import android.content.pm.PackageInfo;
48import android.content.pm.PackageManager;
49import android.content.pm.PackageStats;
50import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
51import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
52import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
53import static android.content.pm.PackageManager.PKG_INSTALL_COMPLETE;
54import static android.content.pm.PackageManager.PKG_INSTALL_INCOMPLETE;
55import android.content.pm.PackageParser;
56import android.content.pm.PermissionInfo;
57import android.content.pm.PermissionGroupInfo;
58import android.content.pm.ProviderInfo;
59import android.content.pm.ResolveInfo;
60import android.content.pm.ServiceInfo;
61import android.content.pm.Signature;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.net.Uri;
63import android.os.Binder;
Dianne Hackborn851a5412009-05-08 12:06:44 -070064import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.os.Bundle;
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080066import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.os.HandlerThread;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -080068import android.os.IBinder;
Suchi Amalapurapu0214e942009-09-02 11:03:18 -070069import android.os.Looper;
70import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import android.os.Parcel;
72import android.os.RemoteException;
73import android.os.Environment;
74import android.os.FileObserver;
75import android.os.FileUtils;
76import android.os.Handler;
San Mehatbe16cb12010-01-29 05:35:35 -080077import android.os.MountServiceResultCode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.ParcelFileDescriptor;
79import android.os.Process;
80import android.os.ServiceManager;
81import android.os.SystemClock;
82import android.os.SystemProperties;
Oscar Montemayord02546b2010-01-14 16:38:40 -080083import android.security.SystemKeyStore;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.util.*;
85import android.view.Display;
86import android.view.WindowManager;
87
88import java.io.File;
89import java.io.FileDescriptor;
90import java.io.FileInputStream;
91import java.io.FileNotFoundException;
92import java.io.FileOutputStream;
93import java.io.FileReader;
94import java.io.FilenameFilter;
95import java.io.IOException;
96import java.io.InputStream;
97import java.io.PrintWriter;
Oscar Montemayord02546b2010-01-14 16:38:40 -080098import java.security.NoSuchAlgorithmException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099import java.util.ArrayList;
100import java.util.Arrays;
Dianne Hackborn49237342009-08-27 20:08:01 -0700101import java.util.Collection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102import java.util.Collections;
103import java.util.Comparator;
104import java.util.Enumeration;
105import java.util.HashMap;
106import java.util.HashSet;
107import java.util.Iterator;
108import java.util.List;
109import java.util.Map;
110import java.util.Set;
111import java.util.zip.ZipEntry;
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -0800112import java.util.zip.ZipException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import java.util.zip.ZipFile;
114import java.util.zip.ZipOutputStream;
115
116class PackageManagerService extends IPackageManager.Stub {
117 private static final String TAG = "PackageManager";
118 private static final boolean DEBUG_SETTINGS = false;
119 private static final boolean DEBUG_PREFERRED = false;
120
121 private static final boolean MULTIPLE_APPLICATION_UIDS = true;
122 private static final int RADIO_UID = Process.PHONE_UID;
Mike Lockwoodd42685d2009-09-03 09:25:22 -0400123 private static final int LOG_UID = Process.LOG_UID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 private static final int FIRST_APPLICATION_UID =
125 Process.FIRST_APPLICATION_UID;
126 private static final int MAX_APPLICATION_UIDS = 1000;
127
128 private static final boolean SHOW_INFO = false;
129
130 private static final boolean GET_CERTIFICATES = true;
131
Oscar Montemayora8529f62009-11-18 10:14:20 -0800132 private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 private static final int REMOVE_EVENTS =
135 FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM;
136 private static final int ADD_EVENTS =
137 FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO;
138
139 private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS;
140
141 static final int SCAN_MONITOR = 1<<0;
142 static final int SCAN_NO_DEX = 1<<1;
143 static final int SCAN_FORCE_DEX = 1<<2;
144 static final int SCAN_UPDATE_SIGNATURE = 1<<3;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -0800145 static final int SCAN_NEW_INSTALL = 1<<4;
146 static final int SCAN_NO_PATHS = 1<<5;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147
148 final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
149 Process.THREAD_PRIORITY_BACKGROUND);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700150 final PackageHandler mHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151
Dianne Hackborn851a5412009-05-08 12:06:44 -0700152 final int mSdkVersion = Build.VERSION.SDK_INT;
153 final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME)
154 ? null : Build.VERSION.CODENAME;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 final Context mContext;
157 final boolean mFactoryTest;
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700158 final boolean mNoDexOpt;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 final DisplayMetrics mMetrics;
160 final int mDefParseFlags;
161 final String[] mSeparateProcesses;
162
163 // This is where all application persistent data goes.
164 final File mAppDataDir;
165
Oscar Montemayora8529f62009-11-18 10:14:20 -0800166 // If Encrypted File System feature is enabled, all application persistent data
167 // should go here instead.
168 final File mSecureAppDataDir;
169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 // This is the object monitoring the framework dir.
171 final FileObserver mFrameworkInstallObserver;
172
173 // This is the object monitoring the system app dir.
174 final FileObserver mSystemInstallObserver;
175
176 // This is the object monitoring mAppInstallDir.
177 final FileObserver mAppInstallObserver;
178
179 // This is the object monitoring mDrmAppPrivateInstallDir.
180 final FileObserver mDrmAppInstallObserver;
181
182 // Used for priviledge escalation. MUST NOT BE CALLED WITH mPackages
183 // LOCK HELD. Can be called with mInstallLock held.
184 final Installer mInstaller;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 final File mFrameworkDir;
187 final File mSystemAppDir;
188 final File mAppInstallDir;
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700189 final File mDalvikCacheDir;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
191 // Directory containing the private parts (e.g. code and non-resource assets) of forward-locked
192 // apps.
193 final File mDrmAppPrivateInstallDir;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 // ----------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 // Lock for state used when installing and doing other long running
198 // operations. Methods that must be called with this lock held have
199 // the prefix "LI".
200 final Object mInstallLock = new Object();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 // These are the directories in the 3rd party applications installed dir
203 // that we have currently loaded packages from. Keys are the application's
204 // installed zip file (absolute codePath), and values are Package.
205 final HashMap<String, PackageParser.Package> mAppDirs =
206 new HashMap<String, PackageParser.Package>();
207
208 // Information for the parser to write more useful error messages.
209 File mScanningPath;
210 int mLastScanError;
211
212 final int[] mOutPermissions = new int[3];
213
214 // ----------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 // Keys are String (package name), values are Package. This also serves
217 // as the lock for the global state. Methods that must be called with
218 // this lock held have the prefix "LP".
219 final HashMap<String, PackageParser.Package> mPackages =
220 new HashMap<String, PackageParser.Package>();
221
222 final Settings mSettings;
223 boolean mRestoredSettings;
224 boolean mReportedUidError;
225
226 // Group-ids that are given to all packages as read from etc/permissions/*.xml.
227 int[] mGlobalGids;
228
229 // These are the built-in uid -> permission mappings that were read from the
230 // etc/permissions.xml file.
231 final SparseArray<HashSet<String>> mSystemPermissions =
232 new SparseArray<HashSet<String>>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 // These are the built-in shared libraries that were read from the
235 // etc/permissions.xml file.
236 final HashMap<String, String> mSharedLibraries = new HashMap<String, String>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800237
Dianne Hackborn49237342009-08-27 20:08:01 -0700238 // Temporary for building the final shared libraries for an .apk.
239 String[] mTmpSharedLibraries = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800240
Dianne Hackborn49237342009-08-27 20:08:01 -0700241 // These are the features this devices supports that were read from the
242 // etc/permissions.xml file.
243 final HashMap<String, FeatureInfo> mAvailableFeatures =
244 new HashMap<String, FeatureInfo>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 // All available activities, for your resolving pleasure.
247 final ActivityIntentResolver mActivities =
248 new ActivityIntentResolver();
249
250 // All available receivers, for your resolving pleasure.
251 final ActivityIntentResolver mReceivers =
252 new ActivityIntentResolver();
253
254 // All available services, for your resolving pleasure.
255 final ServiceIntentResolver mServices = new ServiceIntentResolver();
256
257 // Keys are String (provider class name), values are Provider.
258 final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent =
259 new HashMap<ComponentName, PackageParser.Provider>();
260
261 // Mapping from provider base names (first directory in content URI codePath)
262 // to the provider information.
263 final HashMap<String, PackageParser.Provider> mProviders =
264 new HashMap<String, PackageParser.Provider>();
265
266 // Mapping from instrumentation class names to info about them.
267 final HashMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
268 new HashMap<ComponentName, PackageParser.Instrumentation>();
269
270 // Mapping from permission names to info about them.
271 final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups =
272 new HashMap<String, PackageParser.PermissionGroup>();
273
Dianne Hackborn854060af2009-07-09 18:14:31 -0700274 // Broadcast actions that are only available to the system.
275 final HashSet<String> mProtectedBroadcasts = new HashSet<String>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 boolean mSystemReady;
278 boolean mSafeMode;
279 boolean mHasSystemUidErrors;
280
281 ApplicationInfo mAndroidApplication;
282 final ActivityInfo mResolveActivity = new ActivityInfo();
283 final ResolveInfo mResolveInfo = new ResolveInfo();
284 ComponentName mResolveComponentName;
285 PackageParser.Package mPlatformPackage;
286
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700287 // Set of pending broadcasts for aggregating enable/disable of components.
Dianne Hackborn86a72da2009-11-11 20:12:41 -0800288 final HashMap<String, ArrayList<String>> mPendingBroadcasts
289 = new HashMap<String, ArrayList<String>>();
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700290 static final int SEND_PENDING_BROADCAST = 1;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800291 static final int MCS_BOUND = 3;
292 static final int END_COPY = 4;
293 static final int INIT_COPY = 5;
294 static final int MCS_UNBIND = 6;
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700295 // Delay time in millisecs
296 static final int BROADCAST_DELAY = 10 * 1000;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800297 private ServiceConnection mDefContainerConn = new ServiceConnection() {
298 public void onServiceConnected(ComponentName name, IBinder service) {
299 IMediaContainerService imcs =
300 IMediaContainerService.Stub.asInterface(service);
301 Message msg = mHandler.obtainMessage(MCS_BOUND, imcs);
302 mHandler.sendMessage(msg);
303 }
304
305 public void onServiceDisconnected(ComponentName name) {
306 }
307 };
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700308
309 class PackageHandler extends Handler {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800310 final ArrayList<InstallArgs> mPendingInstalls =
311 new ArrayList<InstallArgs>();
312 // Service Connection to remote media container service to copy
313 // package uri's from external media onto secure containers
314 // or internal storage.
315 private IMediaContainerService mContainerService = null;
316
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700317 PackageHandler(Looper looper) {
318 super(looper);
319 }
320 public void handleMessage(Message msg) {
321 switch (msg.what) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800322 case INIT_COPY: {
323 InstallArgs args = (InstallArgs) msg.obj;
324 args.createCopyFile();
325 Intent service = new Intent().setComponent(new ComponentName(
326 "com.android.defcontainer",
327 "com.android.defcontainer.DefaultContainerService"));
328 if (mContainerService != null) {
329 // No need to add to pending list. Use remote stub directly
330 handleStartCopy(args);
331 } else {
332 if (mContext.bindService(service, mDefContainerConn,
333 Context.BIND_AUTO_CREATE)) {
334 mPendingInstalls.add(args);
335 } else {
336 Log.e(TAG, "Failed to bind to media container service");
337 // Indicate install failure TODO add new error code
338 processPendingInstall(args,
339 PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -0800340 }
341 }
342 break;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800343 }
344 case MCS_BOUND: {
345 // Initialize mContainerService if needed.
346 if (msg.obj != null) {
347 mContainerService = (IMediaContainerService) msg.obj;
348 }
349 if (mPendingInstalls.size() > 0) {
350 InstallArgs args = mPendingInstalls.remove(0);
351 if (args != null) {
352 handleStartCopy(args);
353 }
354 }
355 break;
356 }
357 case MCS_UNBIND : {
358 if (mPendingInstalls.size() == 0) {
359 mContext.unbindService(mDefContainerConn);
360 mContainerService = null;
361 }
362 break;
363 }
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700364 case SEND_PENDING_BROADCAST : {
Dianne Hackborn86a72da2009-11-11 20:12:41 -0800365 String packages[];
366 ArrayList components[];
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700367 int size = 0;
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700368 int uids[];
369 synchronized (mPackages) {
Dianne Hackborn86a72da2009-11-11 20:12:41 -0800370 if (mPendingBroadcasts == null) {
371 return;
372 }
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700373 size = mPendingBroadcasts.size();
374 if (size <= 0) {
375 // Nothing to be done. Just return
376 return;
377 }
Dianne Hackborn86a72da2009-11-11 20:12:41 -0800378 packages = new String[size];
379 components = new ArrayList[size];
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700380 uids = new int[size];
Dianne Hackborn86a72da2009-11-11 20:12:41 -0800381 Iterator<HashMap.Entry<String, ArrayList<String>>>
382 it = mPendingBroadcasts.entrySet().iterator();
383 int i = 0;
384 while (it.hasNext() && i < size) {
385 HashMap.Entry<String, ArrayList<String>> ent = it.next();
386 packages[i] = ent.getKey();
387 components[i] = ent.getValue();
388 PackageSetting ps = mSettings.mPackages.get(ent.getKey());
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700389 uids[i] = (ps != null) ? ps.userId : -1;
Dianne Hackborn86a72da2009-11-11 20:12:41 -0800390 i++;
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700391 }
Dianne Hackborn86a72da2009-11-11 20:12:41 -0800392 size = i;
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700393 mPendingBroadcasts.clear();
394 }
395 // Send broadcasts
396 for (int i = 0; i < size; i++) {
Dianne Hackborn86a72da2009-11-11 20:12:41 -0800397 sendPackageChangedBroadcast(packages[i], true,
398 (ArrayList<String>)components[i], uids[i]);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700399 }
400 break;
401 }
402 }
403 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800404
405 // Utility method to initiate copying apk via media
406 // container service.
407 private void handleStartCopy(InstallArgs args) {
408 int ret = PackageManager.INSTALL_SUCCEEDED;
409 if (mContainerService == null) {
410 // Install error
411 ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
412 } else {
413 ret = args.copyApk(mContainerService);
414 }
415 mHandler.sendEmptyMessage(MCS_UNBIND);
416 processPendingInstall(args, ret);
417 }
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700418 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800419
420 static boolean installOnSd(int flags) {
421 if (((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) ||
422 ((flags & PackageManager.INSTALL_ON_SDCARD) == 0)) {
423 return false;
424 }
425 return true;
426 }
427
428 static boolean isFwdLocked(int flags) {
429 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
430 return true;
431 }
432 return false;
433 }
434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 public static final IPackageManager main(Context context, boolean factoryTest) {
436 PackageManagerService m = new PackageManagerService(context, factoryTest);
437 ServiceManager.addService("package", m);
438 return m;
439 }
440
441 static String[] splitString(String str, char sep) {
442 int count = 1;
443 int i = 0;
444 while ((i=str.indexOf(sep, i)) >= 0) {
445 count++;
446 i++;
447 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 String[] res = new String[count];
450 i=0;
451 count = 0;
452 int lastI=0;
453 while ((i=str.indexOf(sep, i)) >= 0) {
454 res[count] = str.substring(lastI, i);
455 count++;
456 i++;
457 lastI = i;
458 }
459 res[count] = str.substring(lastI, str.length());
460 return res;
461 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 public PackageManagerService(Context context, boolean factoryTest) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800464 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 SystemClock.uptimeMillis());
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 if (mSdkVersion <= 0) {
468 Log.w(TAG, "**** ro.build.version.sdk not set!");
469 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 mContext = context;
472 mFactoryTest = factoryTest;
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700473 mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 mMetrics = new DisplayMetrics();
475 mSettings = new Settings();
476 mSettings.addSharedUserLP("android.uid.system",
477 Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
478 mSettings.addSharedUserLP("android.uid.phone",
479 MULTIPLE_APPLICATION_UIDS
480 ? RADIO_UID : FIRST_APPLICATION_UID,
481 ApplicationInfo.FLAG_SYSTEM);
Mike Lockwoodd42685d2009-09-03 09:25:22 -0400482 mSettings.addSharedUserLP("android.uid.log",
483 MULTIPLE_APPLICATION_UIDS
484 ? LOG_UID : FIRST_APPLICATION_UID,
485 ApplicationInfo.FLAG_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486
487 String separateProcesses = SystemProperties.get("debug.separate_processes");
488 if (separateProcesses != null && separateProcesses.length() > 0) {
489 if ("*".equals(separateProcesses)) {
490 mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
491 mSeparateProcesses = null;
492 Log.w(TAG, "Running with debug.separate_processes: * (ALL)");
493 } else {
494 mDefParseFlags = 0;
495 mSeparateProcesses = separateProcesses.split(",");
496 Log.w(TAG, "Running with debug.separate_processes: "
497 + separateProcesses);
498 }
499 } else {
500 mDefParseFlags = 0;
501 mSeparateProcesses = null;
502 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 Installer installer = new Installer();
505 // Little hacky thing to check if installd is here, to determine
506 // whether we are running on the simulator and thus need to take
507 // care of building the /data file structure ourself.
508 // (apparently the sim now has a working installer)
509 if (installer.ping() && Process.supportsProcesses()) {
510 mInstaller = installer;
511 } else {
512 mInstaller = null;
513 }
514
515 WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
516 Display d = wm.getDefaultDisplay();
517 d.getMetrics(mMetrics);
518
519 synchronized (mInstallLock) {
520 synchronized (mPackages) {
521 mHandlerThread.start();
Suchi Amalapurapu0214e942009-09-02 11:03:18 -0700522 mHandler = new PackageHandler(mHandlerThread.getLooper());
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 File dataDir = Environment.getDataDirectory();
525 mAppDataDir = new File(dataDir, "data");
Oscar Montemayora8529f62009-11-18 10:14:20 -0800526 mSecureAppDataDir = new File(dataDir, "secure/data");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
528
529 if (mInstaller == null) {
530 // Make sure these dirs exist, when we are running in
531 // the simulator.
532 // Make a wide-open directory for random misc stuff.
533 File miscDir = new File(dataDir, "misc");
534 miscDir.mkdirs();
535 mAppDataDir.mkdirs();
Oscar Montemayora8529f62009-11-18 10:14:20 -0800536 mSecureAppDataDir.mkdirs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 mDrmAppPrivateInstallDir.mkdirs();
538 }
539
540 readPermissions();
541
542 mRestoredSettings = mSettings.readLP();
543 long startTime = SystemClock.uptimeMillis();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800544
545 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 startTime);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800547
Suchi Amalapurapudaec17222010-01-14 21:25:16 -0800548 // Set flag to monitor and not change apk file paths when
549 // scanning install directories.
550 int scanMode = SCAN_MONITOR | SCAN_NO_PATHS;
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700551 if (mNoDexOpt) {
552 Log.w(TAG, "Running ENG build: no pre-dexopt!");
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800553 scanMode |= SCAN_NO_DEX;
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700554 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 final HashSet<String> libFiles = new HashSet<String>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700559 mDalvikCacheDir = new File(dataDir, "dalvik-cache");
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 if (mInstaller != null) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700562 boolean didDexOpt = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 /**
565 * Out of paranoia, ensure that everything in the boot class
566 * path has been dexed.
567 */
568 String bootClassPath = System.getProperty("java.boot.class.path");
569 if (bootClassPath != null) {
570 String[] paths = splitString(bootClassPath, ':');
571 for (int i=0; i<paths.length; i++) {
572 try {
573 if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
574 libFiles.add(paths[i]);
575 mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700576 didDexOpt = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578 } catch (FileNotFoundException e) {
579 Log.w(TAG, "Boot class path not found: " + paths[i]);
580 } catch (IOException e) {
581 Log.w(TAG, "Exception reading boot class path: " + paths[i], e);
582 }
583 }
584 } else {
585 Log.w(TAG, "No BOOTCLASSPATH found!");
586 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 /**
589 * Also ensure all external libraries have had dexopt run on them.
590 */
591 if (mSharedLibraries.size() > 0) {
592 Iterator<String> libs = mSharedLibraries.values().iterator();
593 while (libs.hasNext()) {
594 String lib = libs.next();
595 try {
596 if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
597 libFiles.add(lib);
598 mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700599 didDexOpt = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 }
601 } catch (FileNotFoundException e) {
602 Log.w(TAG, "Library not found: " + lib);
603 } catch (IOException e) {
604 Log.w(TAG, "Exception reading library: " + lib, e);
605 }
606 }
607 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 // Gross hack for now: we know this file doesn't contain any
610 // code, so don't dexopt it to avoid the resulting log spew.
611 libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 /**
614 * And there are a number of commands implemented in Java, which
615 * we currently need to do the dexopt on so that they can be
616 * run from a non-root shell.
617 */
618 String[] frameworkFiles = mFrameworkDir.list();
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700619 if (frameworkFiles != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 for (int i=0; i<frameworkFiles.length; i++) {
621 File libPath = new File(mFrameworkDir, frameworkFiles[i]);
622 String path = libPath.getPath();
623 // Skip the file if we alrady did it.
624 if (libFiles.contains(path)) {
625 continue;
626 }
627 // Skip the file if it is not a type we want to dexopt.
628 if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
629 continue;
630 }
631 try {
632 if (dalvik.system.DexFile.isDexOptNeeded(path)) {
633 mInstaller.dexopt(path, Process.SYSTEM_UID, true);
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700634 didDexOpt = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 }
636 } catch (FileNotFoundException e) {
637 Log.w(TAG, "Jar not found: " + path);
638 } catch (IOException e) {
639 Log.w(TAG, "Exception reading jar: " + path, e);
640 }
641 }
642 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800643
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700644 if (didDexOpt) {
645 // If we had to do a dexopt of one of the previous
646 // things, then something on the system has changed.
647 // Consider this significant, and wipe away all other
648 // existing dexopt files to ensure we don't leave any
649 // dangling around.
650 String[] files = mDalvikCacheDir.list();
651 if (files != null) {
652 for (int i=0; i<files.length; i++) {
653 String fn = files[i];
654 if (fn.startsWith("data@app@")
655 || fn.startsWith("data@app-private@")) {
656 Log.i(TAG, "Pruning dalvik file: " + fn);
657 (new File(mDalvikCacheDir, fn)).delete();
658 }
659 }
660 }
661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 mFrameworkInstallObserver = new AppDirObserver(
665 mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
666 mFrameworkInstallObserver.startWatching();
667 scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM,
Suchi Amalapurapudaec17222010-01-14 21:25:16 -0800668 scanMode | SCAN_NO_DEX);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 mSystemAppDir = new File(Environment.getRootDirectory(), "app");
670 mSystemInstallObserver = new AppDirObserver(
671 mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
672 mSystemInstallObserver.startWatching();
Suchi Amalapurapudaec17222010-01-14 21:25:16 -0800673 scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 mAppInstallDir = new File(dataDir, "app");
675 if (mInstaller == null) {
676 // Make sure these dirs exist, when we are running in
677 // the simulator.
678 mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists
679 }
680 //look for any incomplete package installations
Oscar Montemayora8529f62009-11-18 10:14:20 -0800681 ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackages();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 //clean up list
683 for(int i = 0; i < deletePkgsList.size(); i++) {
684 //clean up here
685 cleanupInstallFailedPackage(deletePkgsList.get(i));
686 }
687 //delete tmp files
688 deleteTempPackageFiles();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800689
690 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 SystemClock.uptimeMillis());
692 mAppInstallObserver = new AppDirObserver(
693 mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
694 mAppInstallObserver.startWatching();
695 scanDirLI(mAppInstallDir, 0, scanMode);
696
697 mDrmAppInstallObserver = new AppDirObserver(
698 mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
699 mDrmAppInstallObserver.startWatching();
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -0800700 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800702 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 SystemClock.uptimeMillis());
704 Log.i(TAG, "Time to scan packages: "
705 + ((SystemClock.uptimeMillis()-startTime)/1000f)
706 + " seconds");
707
708 updatePermissionsLP();
709
710 mSettings.writeLP();
711
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800712 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 SystemClock.uptimeMillis());
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 // Now after opening every single application zip, make sure they
716 // are all flushed. Not really needed, but keeps things nice and
717 // tidy.
718 Runtime.getRuntime().gc();
719 } // synchronized (mPackages)
720 } // synchronized (mInstallLock)
721 }
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 @Override
724 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
725 throws RemoteException {
726 try {
727 return super.onTransact(code, data, reply, flags);
728 } catch (RuntimeException e) {
729 if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) {
730 Log.e(TAG, "Package Manager Crash", e);
731 }
732 throw e;
733 }
734 }
735
Dianne Hackborne6620b22010-01-22 14:46:21 -0800736 void cleanupInstallFailedPackage(PackageSetting ps) {
737 Log.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 if (mInstaller != null) {
Kenny Rootbdbc9252010-01-28 12:03:49 -0800739 boolean useSecureFS = useEncryptedFilesystemForPackage(ps.pkg);
740 int retCode = mInstaller.remove(ps.name, useSecureFS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 if (retCode < 0) {
742 Log.w(TAG, "Couldn't remove app data directory for package: "
Dianne Hackborne6620b22010-01-22 14:46:21 -0800743 + ps.name + ", retcode=" + retCode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 }
745 } else {
746 //for emulator
Dianne Hackborne6620b22010-01-22 14:46:21 -0800747 PackageParser.Package pkg = mPackages.get(ps.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 File dataDir = new File(pkg.applicationInfo.dataDir);
749 dataDir.delete();
750 }
Dianne Hackborne6620b22010-01-22 14:46:21 -0800751 if (ps.codePath != null) {
752 if (!ps.codePath.delete()) {
753 Log.w(TAG, "Unable to remove old code file: " + ps.codePath);
754 }
755 }
756 if (ps.resourcePath != null) {
757 if (!ps.resourcePath.delete() && !ps.resourcePath.equals(ps.codePath)) {
758 Log.w(TAG, "Unable to remove old code file: " + ps.resourcePath);
759 }
760 }
761 mSettings.removePackageLP(ps.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 }
763
764 void readPermissions() {
765 // Read permissions from .../etc/permission directory.
766 File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
767 if (!libraryDir.exists() || !libraryDir.isDirectory()) {
768 Log.w(TAG, "No directory " + libraryDir + ", skipping");
769 return;
770 }
771 if (!libraryDir.canRead()) {
772 Log.w(TAG, "Directory " + libraryDir + " cannot be read");
773 return;
774 }
775
776 // Iterate over the files in the directory and scan .xml files
777 for (File f : libraryDir.listFiles()) {
778 // We'll read platform.xml last
779 if (f.getPath().endsWith("etc/permissions/platform.xml")) {
780 continue;
781 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 if (!f.getPath().endsWith(".xml")) {
784 Log.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
785 continue;
786 }
787 if (!f.canRead()) {
788 Log.w(TAG, "Permissions library file " + f + " cannot be read");
789 continue;
790 }
791
792 readPermissionsFromXml(f);
793 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
796 final File permFile = new File(Environment.getRootDirectory(),
797 "etc/permissions/platform.xml");
798 readPermissionsFromXml(permFile);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800799
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700800 StringBuilder sb = new StringBuilder(128);
801 sb.append("Libs:");
802 Iterator<String> it = mSharedLibraries.keySet().iterator();
803 while (it.hasNext()) {
804 sb.append(' ');
805 String name = it.next();
806 sb.append(name);
807 sb.append(':');
808 sb.append(mSharedLibraries.get(name));
809 }
810 Log.i(TAG, sb.toString());
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800811
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700812 sb.setLength(0);
813 sb.append("Features:");
814 it = mAvailableFeatures.keySet().iterator();
815 while (it.hasNext()) {
816 sb.append(' ');
817 sb.append(it.next());
818 }
819 Log.i(TAG, sb.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800821
822 private void readPermissionsFromXml(File permFile) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 FileReader permReader = null;
824 try {
825 permReader = new FileReader(permFile);
826 } catch (FileNotFoundException e) {
827 Log.w(TAG, "Couldn't find or open permissions file " + permFile);
828 return;
829 }
830
831 try {
832 XmlPullParser parser = Xml.newPullParser();
833 parser.setInput(permReader);
834
835 XmlUtils.beginDocument(parser, "permissions");
836
837 while (true) {
838 XmlUtils.nextElement(parser);
839 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
840 break;
841 }
842
843 String name = parser.getName();
844 if ("group".equals(name)) {
845 String gidStr = parser.getAttributeValue(null, "gid");
846 if (gidStr != null) {
847 int gid = Integer.parseInt(gidStr);
848 mGlobalGids = appendInt(mGlobalGids, gid);
849 } else {
850 Log.w(TAG, "<group> without gid at "
851 + parser.getPositionDescription());
852 }
853
854 XmlUtils.skipCurrentTag(parser);
855 continue;
856 } else if ("permission".equals(name)) {
857 String perm = parser.getAttributeValue(null, "name");
858 if (perm == null) {
859 Log.w(TAG, "<permission> without name at "
860 + parser.getPositionDescription());
861 XmlUtils.skipCurrentTag(parser);
862 continue;
863 }
864 perm = perm.intern();
865 readPermission(parser, perm);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 } else if ("assign-permission".equals(name)) {
868 String perm = parser.getAttributeValue(null, "name");
869 if (perm == null) {
870 Log.w(TAG, "<assign-permission> without name at "
871 + parser.getPositionDescription());
872 XmlUtils.skipCurrentTag(parser);
873 continue;
874 }
875 String uidStr = parser.getAttributeValue(null, "uid");
876 if (uidStr == null) {
877 Log.w(TAG, "<assign-permission> without uid at "
878 + parser.getPositionDescription());
879 XmlUtils.skipCurrentTag(parser);
880 continue;
881 }
882 int uid = Process.getUidForName(uidStr);
883 if (uid < 0) {
884 Log.w(TAG, "<assign-permission> with unknown uid \""
885 + uidStr + "\" at "
886 + parser.getPositionDescription());
887 XmlUtils.skipCurrentTag(parser);
888 continue;
889 }
890 perm = perm.intern();
891 HashSet<String> perms = mSystemPermissions.get(uid);
892 if (perms == null) {
893 perms = new HashSet<String>();
894 mSystemPermissions.put(uid, perms);
895 }
896 perms.add(perm);
897 XmlUtils.skipCurrentTag(parser);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 } else if ("library".equals(name)) {
900 String lname = parser.getAttributeValue(null, "name");
901 String lfile = parser.getAttributeValue(null, "file");
902 if (lname == null) {
903 Log.w(TAG, "<library> without name at "
904 + parser.getPositionDescription());
905 } else if (lfile == null) {
906 Log.w(TAG, "<library> without file at "
907 + parser.getPositionDescription());
908 } else {
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700909 //Log.i(TAG, "Got library " + lname + " in " + lfile);
Dianne Hackborn49237342009-08-27 20:08:01 -0700910 mSharedLibraries.put(lname, lfile);
911 }
912 XmlUtils.skipCurrentTag(parser);
913 continue;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800914
Dianne Hackborn49237342009-08-27 20:08:01 -0700915 } else if ("feature".equals(name)) {
916 String fname = parser.getAttributeValue(null, "name");
917 if (fname == null) {
918 Log.w(TAG, "<feature> without name at "
919 + parser.getPositionDescription());
920 } else {
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700921 //Log.i(TAG, "Got feature " + fname);
Dianne Hackborn49237342009-08-27 20:08:01 -0700922 FeatureInfo fi = new FeatureInfo();
923 fi.name = fname;
924 mAvailableFeatures.put(fname, fi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 }
926 XmlUtils.skipCurrentTag(parser);
927 continue;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 } else {
930 XmlUtils.skipCurrentTag(parser);
931 continue;
932 }
933
934 }
935 } catch (XmlPullParserException e) {
936 Log.w(TAG, "Got execption parsing permissions.", e);
937 } catch (IOException e) {
938 Log.w(TAG, "Got execption parsing permissions.", e);
939 }
940 }
941
942 void readPermission(XmlPullParser parser, String name)
943 throws IOException, XmlPullParserException {
944
945 name = name.intern();
946
947 BasePermission bp = mSettings.mPermissions.get(name);
948 if (bp == null) {
949 bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);
950 mSettings.mPermissions.put(name, bp);
951 }
952 int outerDepth = parser.getDepth();
953 int type;
954 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
955 && (type != XmlPullParser.END_TAG
956 || parser.getDepth() > outerDepth)) {
957 if (type == XmlPullParser.END_TAG
958 || type == XmlPullParser.TEXT) {
959 continue;
960 }
961
962 String tagName = parser.getName();
963 if ("group".equals(tagName)) {
964 String gidStr = parser.getAttributeValue(null, "gid");
965 if (gidStr != null) {
966 int gid = Process.getGidForName(gidStr);
967 bp.gids = appendInt(bp.gids, gid);
968 } else {
969 Log.w(TAG, "<group> without gid at "
970 + parser.getPositionDescription());
971 }
972 }
973 XmlUtils.skipCurrentTag(parser);
974 }
975 }
976
977 static int[] appendInt(int[] cur, int val) {
978 if (cur == null) {
979 return new int[] { val };
980 }
981 final int N = cur.length;
982 for (int i=0; i<N; i++) {
983 if (cur[i] == val) {
984 return cur;
985 }
986 }
987 int[] ret = new int[N+1];
988 System.arraycopy(cur, 0, ret, 0, N);
989 ret[N] = val;
990 return ret;
991 }
992
993 static int[] appendInts(int[] cur, int[] add) {
994 if (add == null) return cur;
995 if (cur == null) return add;
996 final int N = add.length;
997 for (int i=0; i<N; i++) {
998 cur = appendInt(cur, add[i]);
999 }
1000 return cur;
1001 }
1002
1003 PackageInfo generatePackageInfo(PackageParser.Package p, int flags) {
Suchi Amalapurapub897cff2009-10-14 12:11:48 -07001004 if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1005 // The package has been uninstalled but has retained data and resources.
1006 return PackageParser.generatePackageInfo(p, null, flags);
1007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 final PackageSetting ps = (PackageSetting)p.mExtras;
1009 if (ps == null) {
1010 return null;
1011 }
1012 final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
1013 return PackageParser.generatePackageInfo(p, gp.gids, flags);
1014 }
1015
1016 public PackageInfo getPackageInfo(String packageName, int flags) {
1017 synchronized (mPackages) {
1018 PackageParser.Package p = mPackages.get(packageName);
1019 if (Config.LOGV) Log.v(
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07001020 TAG, "getPackageInfo " + packageName
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 + ": " + p);
1022 if (p != null) {
1023 return generatePackageInfo(p, flags);
1024 }
1025 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1026 return generatePackageInfoFromSettingsLP(packageName, flags);
1027 }
1028 }
1029 return null;
1030 }
1031
1032 public int getPackageUid(String packageName) {
1033 synchronized (mPackages) {
1034 PackageParser.Package p = mPackages.get(packageName);
1035 if(p != null) {
1036 return p.applicationInfo.uid;
1037 }
1038 PackageSetting ps = mSettings.mPackages.get(packageName);
1039 if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) {
1040 return -1;
1041 }
1042 p = ps.pkg;
1043 return p != null ? p.applicationInfo.uid : -1;
1044 }
1045 }
1046
1047 public int[] getPackageGids(String packageName) {
1048 synchronized (mPackages) {
1049 PackageParser.Package p = mPackages.get(packageName);
1050 if (Config.LOGV) Log.v(
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07001051 TAG, "getPackageGids" + packageName
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 + ": " + p);
1053 if (p != null) {
1054 final PackageSetting ps = (PackageSetting)p.mExtras;
1055 final SharedUserSetting suid = ps.sharedUser;
1056 return suid != null ? suid.gids : ps.gids;
1057 }
1058 }
1059 // stupid thing to indicate an error.
1060 return new int[0];
1061 }
1062
1063 public PermissionInfo getPermissionInfo(String name, int flags) {
1064 synchronized (mPackages) {
1065 final BasePermission p = mSettings.mPermissions.get(name);
1066 if (p != null && p.perm != null) {
1067 return PackageParser.generatePermissionInfo(p.perm, flags);
1068 }
1069 return null;
1070 }
1071 }
1072
1073 public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
1074 synchronized (mPackages) {
1075 ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
1076 for (BasePermission p : mSettings.mPermissions.values()) {
1077 if (group == null) {
1078 if (p.perm.info.group == null) {
1079 out.add(PackageParser.generatePermissionInfo(p.perm, flags));
1080 }
1081 } else {
1082 if (group.equals(p.perm.info.group)) {
1083 out.add(PackageParser.generatePermissionInfo(p.perm, flags));
1084 }
1085 }
1086 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 if (out.size() > 0) {
1089 return out;
1090 }
1091 return mPermissionGroups.containsKey(group) ? out : null;
1092 }
1093 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
1096 synchronized (mPackages) {
1097 return PackageParser.generatePermissionGroupInfo(
1098 mPermissionGroups.get(name), flags);
1099 }
1100 }
1101
1102 public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
1103 synchronized (mPackages) {
1104 final int N = mPermissionGroups.size();
1105 ArrayList<PermissionGroupInfo> out
1106 = new ArrayList<PermissionGroupInfo>(N);
1107 for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) {
1108 out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
1109 }
1110 return out;
1111 }
1112 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) {
1115 PackageSetting ps = mSettings.mPackages.get(packageName);
1116 if(ps != null) {
1117 if(ps.pkg == null) {
1118 PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags);
1119 if(pInfo != null) {
1120 return pInfo.applicationInfo;
1121 }
1122 return null;
1123 }
1124 return PackageParser.generateApplicationInfo(ps.pkg, flags);
1125 }
1126 return null;
1127 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) {
1130 PackageSetting ps = mSettings.mPackages.get(packageName);
1131 if(ps != null) {
1132 if(ps.pkg == null) {
1133 ps.pkg = new PackageParser.Package(packageName);
1134 ps.pkg.applicationInfo.packageName = packageName;
1135 }
1136 return generatePackageInfo(ps.pkg, flags);
1137 }
1138 return null;
1139 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 public ApplicationInfo getApplicationInfo(String packageName, int flags) {
1142 synchronized (mPackages) {
1143 PackageParser.Package p = mPackages.get(packageName);
1144 if (Config.LOGV) Log.v(
1145 TAG, "getApplicationInfo " + packageName
1146 + ": " + p);
1147 if (p != null) {
1148 // Note: isEnabledLP() does not apply here - always return info
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07001149 return PackageParser.generateApplicationInfo(p, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 }
1151 if ("android".equals(packageName)||"system".equals(packageName)) {
1152 return mAndroidApplication;
1153 }
1154 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1155 return generateApplicationInfoFromSettingsLP(packageName, flags);
1156 }
1157 }
1158 return null;
1159 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001160
1161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) {
1163 mContext.enforceCallingOrSelfPermission(
1164 android.Manifest.permission.CLEAR_APP_CACHE, null);
1165 // Queue up an async operation since clearing cache may take a little while.
1166 mHandler.post(new Runnable() {
1167 public void run() {
1168 mHandler.removeCallbacks(this);
1169 int retCode = -1;
1170 if (mInstaller != null) {
1171 retCode = mInstaller.freeCache(freeStorageSize);
1172 if (retCode < 0) {
1173 Log.w(TAG, "Couldn't clear application caches");
1174 }
1175 } //end if mInstaller
1176 if (observer != null) {
1177 try {
1178 observer.onRemoveCompleted(null, (retCode >= 0));
1179 } catch (RemoteException e) {
1180 Log.w(TAG, "RemoveException when invoking call back");
1181 }
1182 }
1183 }
1184 });
1185 }
1186
Suchi Amalapurapubc806f62009-06-17 15:18:19 -07001187 public void freeStorage(final long freeStorageSize, final IntentSender pi) {
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -07001188 mContext.enforceCallingOrSelfPermission(
1189 android.Manifest.permission.CLEAR_APP_CACHE, null);
1190 // Queue up an async operation since clearing cache may take a little while.
1191 mHandler.post(new Runnable() {
1192 public void run() {
1193 mHandler.removeCallbacks(this);
1194 int retCode = -1;
1195 if (mInstaller != null) {
1196 retCode = mInstaller.freeCache(freeStorageSize);
1197 if (retCode < 0) {
1198 Log.w(TAG, "Couldn't clear application caches");
1199 }
1200 }
1201 if(pi != null) {
1202 try {
1203 // Callback via pending intent
1204 int code = (retCode >= 0) ? 1 : 0;
1205 pi.sendIntent(null, code, null,
1206 null, null);
1207 } catch (SendIntentException e1) {
1208 Log.i(TAG, "Failed to send pending intent");
1209 }
1210 }
1211 }
1212 });
1213 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 public ActivityInfo getActivityInfo(ComponentName component, int flags) {
1216 synchronized (mPackages) {
1217 PackageParser.Activity a = mActivities.mActivities.get(component);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07001218
1219 if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 if (a != null && mSettings.isEnabledLP(a.info, flags)) {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001221 return PackageParser.generateActivityInfo(a, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 }
1223 if (mResolveComponentName.equals(component)) {
1224 return mResolveActivity;
1225 }
1226 }
1227 return null;
1228 }
1229
1230 public ActivityInfo getReceiverInfo(ComponentName component, int flags) {
1231 synchronized (mPackages) {
1232 PackageParser.Activity a = mReceivers.mActivities.get(component);
1233 if (Config.LOGV) Log.v(
1234 TAG, "getReceiverInfo " + component + ": " + a);
1235 if (a != null && mSettings.isEnabledLP(a.info, flags)) {
1236 return PackageParser.generateActivityInfo(a, flags);
1237 }
1238 }
1239 return null;
1240 }
1241
1242 public ServiceInfo getServiceInfo(ComponentName component, int flags) {
1243 synchronized (mPackages) {
1244 PackageParser.Service s = mServices.mServices.get(component);
1245 if (Config.LOGV) Log.v(
1246 TAG, "getServiceInfo " + component + ": " + s);
1247 if (s != null && mSettings.isEnabledLP(s.info, flags)) {
1248 return PackageParser.generateServiceInfo(s, flags);
1249 }
1250 }
1251 return null;
1252 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 public String[] getSystemSharedLibraryNames() {
1255 Set<String> libSet;
1256 synchronized (mPackages) {
1257 libSet = mSharedLibraries.keySet();
Dianne Hackborn49237342009-08-27 20:08:01 -07001258 int size = libSet.size();
1259 if (size > 0) {
1260 String[] libs = new String[size];
1261 libSet.toArray(libs);
1262 return libs;
1263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 }
Dianne Hackborn49237342009-08-27 20:08:01 -07001265 return null;
1266 }
1267
1268 public FeatureInfo[] getSystemAvailableFeatures() {
1269 Collection<FeatureInfo> featSet;
1270 synchronized (mPackages) {
1271 featSet = mAvailableFeatures.values();
1272 int size = featSet.size();
1273 if (size > 0) {
1274 FeatureInfo[] features = new FeatureInfo[size+1];
1275 featSet.toArray(features);
1276 FeatureInfo fi = new FeatureInfo();
1277 fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
1278 FeatureInfo.GL_ES_VERSION_UNDEFINED);
1279 features[size] = fi;
1280 return features;
1281 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 }
1283 return null;
1284 }
1285
Dianne Hackborn039c68e2009-09-26 16:39:23 -07001286 public boolean hasSystemFeature(String name) {
1287 synchronized (mPackages) {
1288 return mAvailableFeatures.containsKey(name);
1289 }
1290 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 public int checkPermission(String permName, String pkgName) {
1293 synchronized (mPackages) {
1294 PackageParser.Package p = mPackages.get(pkgName);
1295 if (p != null && p.mExtras != null) {
1296 PackageSetting ps = (PackageSetting)p.mExtras;
1297 if (ps.sharedUser != null) {
1298 if (ps.sharedUser.grantedPermissions.contains(permName)) {
1299 return PackageManager.PERMISSION_GRANTED;
1300 }
1301 } else if (ps.grantedPermissions.contains(permName)) {
1302 return PackageManager.PERMISSION_GRANTED;
1303 }
1304 }
1305 }
1306 return PackageManager.PERMISSION_DENIED;
1307 }
1308
1309 public int checkUidPermission(String permName, int uid) {
1310 synchronized (mPackages) {
1311 Object obj = mSettings.getUserIdLP(uid);
1312 if (obj != null) {
1313 if (obj instanceof SharedUserSetting) {
1314 SharedUserSetting sus = (SharedUserSetting)obj;
1315 if (sus.grantedPermissions.contains(permName)) {
1316 return PackageManager.PERMISSION_GRANTED;
1317 }
1318 } else if (obj instanceof PackageSetting) {
1319 PackageSetting ps = (PackageSetting)obj;
1320 if (ps.grantedPermissions.contains(permName)) {
1321 return PackageManager.PERMISSION_GRANTED;
1322 }
1323 }
1324 } else {
1325 HashSet<String> perms = mSystemPermissions.get(uid);
1326 if (perms != null && perms.contains(permName)) {
1327 return PackageManager.PERMISSION_GRANTED;
1328 }
1329 }
1330 }
1331 return PackageManager.PERMISSION_DENIED;
1332 }
1333
1334 private BasePermission findPermissionTreeLP(String permName) {
1335 for(BasePermission bp : mSettings.mPermissionTrees.values()) {
1336 if (permName.startsWith(bp.name) &&
1337 permName.length() > bp.name.length() &&
1338 permName.charAt(bp.name.length()) == '.') {
1339 return bp;
1340 }
1341 }
1342 return null;
1343 }
1344
1345 private BasePermission checkPermissionTreeLP(String permName) {
1346 if (permName != null) {
1347 BasePermission bp = findPermissionTreeLP(permName);
1348 if (bp != null) {
1349 if (bp.uid == Binder.getCallingUid()) {
1350 return bp;
1351 }
1352 throw new SecurityException("Calling uid "
1353 + Binder.getCallingUid()
1354 + " is not allowed to add to permission tree "
1355 + bp.name + " owned by uid " + bp.uid);
1356 }
1357 }
1358 throw new SecurityException("No permission tree found for " + permName);
1359 }
1360
1361 public boolean addPermission(PermissionInfo info) {
1362 synchronized (mPackages) {
1363 if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
1364 throw new SecurityException("Label must be specified in permission");
1365 }
1366 BasePermission tree = checkPermissionTreeLP(info.name);
1367 BasePermission bp = mSettings.mPermissions.get(info.name);
1368 boolean added = bp == null;
1369 if (added) {
1370 bp = new BasePermission(info.name, tree.sourcePackage,
1371 BasePermission.TYPE_DYNAMIC);
1372 } else if (bp.type != BasePermission.TYPE_DYNAMIC) {
1373 throw new SecurityException(
1374 "Not allowed to modify non-dynamic permission "
1375 + info.name);
1376 }
1377 bp.perm = new PackageParser.Permission(tree.perm.owner,
1378 new PermissionInfo(info));
1379 bp.perm.info.packageName = tree.perm.info.packageName;
1380 bp.uid = tree.uid;
1381 if (added) {
1382 mSettings.mPermissions.put(info.name, bp);
1383 }
1384 mSettings.writeLP();
1385 return added;
1386 }
1387 }
1388
1389 public void removePermission(String name) {
1390 synchronized (mPackages) {
1391 checkPermissionTreeLP(name);
1392 BasePermission bp = mSettings.mPermissions.get(name);
1393 if (bp != null) {
1394 if (bp.type != BasePermission.TYPE_DYNAMIC) {
1395 throw new SecurityException(
1396 "Not allowed to modify non-dynamic permission "
1397 + name);
1398 }
1399 mSettings.mPermissions.remove(name);
1400 mSettings.writeLP();
1401 }
1402 }
1403 }
1404
Dianne Hackborn854060af2009-07-09 18:14:31 -07001405 public boolean isProtectedBroadcast(String actionName) {
1406 synchronized (mPackages) {
1407 return mProtectedBroadcasts.contains(actionName);
1408 }
1409 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 public int checkSignatures(String pkg1, String pkg2) {
1412 synchronized (mPackages) {
1413 PackageParser.Package p1 = mPackages.get(pkg1);
1414 PackageParser.Package p2 = mPackages.get(pkg2);
1415 if (p1 == null || p1.mExtras == null
1416 || p2 == null || p2.mExtras == null) {
1417 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
1418 }
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07001419 return checkSignaturesLP(p1.mSignatures, p2.mSignatures);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 }
1421 }
1422
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07001423 public int checkUidSignatures(int uid1, int uid2) {
1424 synchronized (mPackages) {
1425 Signature[] s1;
1426 Signature[] s2;
1427 Object obj = mSettings.getUserIdLP(uid1);
1428 if (obj != null) {
1429 if (obj instanceof SharedUserSetting) {
1430 s1 = ((SharedUserSetting)obj).signatures.mSignatures;
1431 } else if (obj instanceof PackageSetting) {
1432 s1 = ((PackageSetting)obj).signatures.mSignatures;
1433 } else {
1434 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
1435 }
1436 } else {
1437 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
1438 }
1439 obj = mSettings.getUserIdLP(uid2);
1440 if (obj != null) {
1441 if (obj instanceof SharedUserSetting) {
1442 s2 = ((SharedUserSetting)obj).signatures.mSignatures;
1443 } else if (obj instanceof PackageSetting) {
1444 s2 = ((PackageSetting)obj).signatures.mSignatures;
1445 } else {
1446 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
1447 }
1448 } else {
1449 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
1450 }
1451 return checkSignaturesLP(s1, s2);
1452 }
1453 }
1454
1455 int checkSignaturesLP(Signature[] s1, Signature[] s2) {
1456 if (s1 == null) {
1457 return s2 == null
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 ? PackageManager.SIGNATURE_NEITHER_SIGNED
1459 : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
1460 }
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07001461 if (s2 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
1463 }
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07001464 final int N1 = s1.length;
1465 final int N2 = s2.length;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 for (int i=0; i<N1; i++) {
1467 boolean match = false;
1468 for (int j=0; j<N2; j++) {
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07001469 if (s1[i].equals(s2[j])) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 match = true;
1471 break;
1472 }
1473 }
1474 if (!match) {
1475 return PackageManager.SIGNATURE_NO_MATCH;
1476 }
1477 }
1478 return PackageManager.SIGNATURE_MATCH;
1479 }
1480
1481 public String[] getPackagesForUid(int uid) {
1482 synchronized (mPackages) {
1483 Object obj = mSettings.getUserIdLP(uid);
1484 if (obj instanceof SharedUserSetting) {
1485 SharedUserSetting sus = (SharedUserSetting)obj;
1486 final int N = sus.packages.size();
1487 String[] res = new String[N];
1488 Iterator<PackageSetting> it = sus.packages.iterator();
1489 int i=0;
1490 while (it.hasNext()) {
1491 res[i++] = it.next().name;
1492 }
1493 return res;
1494 } else if (obj instanceof PackageSetting) {
1495 PackageSetting ps = (PackageSetting)obj;
1496 return new String[] { ps.name };
1497 }
1498 }
1499 return null;
1500 }
1501
1502 public String getNameForUid(int uid) {
1503 synchronized (mPackages) {
1504 Object obj = mSettings.getUserIdLP(uid);
1505 if (obj instanceof SharedUserSetting) {
1506 SharedUserSetting sus = (SharedUserSetting)obj;
1507 return sus.name + ":" + sus.userId;
1508 } else if (obj instanceof PackageSetting) {
1509 PackageSetting ps = (PackageSetting)obj;
1510 return ps.name;
1511 }
1512 }
1513 return null;
1514 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 public int getUidForSharedUser(String sharedUserName) {
1517 if(sharedUserName == null) {
1518 return -1;
1519 }
1520 synchronized (mPackages) {
1521 SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false);
1522 if(suid == null) {
1523 return -1;
1524 }
1525 return suid.userId;
1526 }
1527 }
1528
1529 public ResolveInfo resolveIntent(Intent intent, String resolvedType,
1530 int flags) {
1531 List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags);
Mihai Predaeae850c2009-05-13 10:13:48 +02001532 return chooseBestActivity(intent, resolvedType, flags, query);
1533 }
1534
Mihai Predaeae850c2009-05-13 10:13:48 +02001535 private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
1536 int flags, List<ResolveInfo> query) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 if (query != null) {
1538 final int N = query.size();
1539 if (N == 1) {
1540 return query.get(0);
1541 } else if (N > 1) {
1542 // If there is more than one activity with the same priority,
1543 // then let the user decide between them.
1544 ResolveInfo r0 = query.get(0);
1545 ResolveInfo r1 = query.get(1);
1546 if (false) {
1547 System.out.println(r0.activityInfo.name +
1548 "=" + r0.priority + " vs " +
1549 r1.activityInfo.name +
1550 "=" + r1.priority);
1551 }
1552 // If the first activity has a higher priority, or a different
1553 // default, then it is always desireable to pick it.
1554 if (r0.priority != r1.priority
1555 || r0.preferredOrder != r1.preferredOrder
1556 || r0.isDefault != r1.isDefault) {
1557 return query.get(0);
1558 }
1559 // If we have saved a preference for a preferred activity for
1560 // this Intent, use that.
1561 ResolveInfo ri = findPreferredActivity(intent, resolvedType,
1562 flags, query, r0.priority);
1563 if (ri != null) {
1564 return ri;
1565 }
1566 return mResolveInfo;
1567 }
1568 }
1569 return null;
1570 }
1571
1572 ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
1573 int flags, List<ResolveInfo> query, int priority) {
1574 synchronized (mPackages) {
1575 if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
1576 List<PreferredActivity> prefs =
Mihai Preda074edef2009-05-18 17:13:31 +02001577 mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
1579 if (prefs != null && prefs.size() > 0) {
1580 // First figure out how good the original match set is.
1581 // We will only allow preferred activities that came
1582 // from the same match quality.
1583 int match = 0;
1584 final int N = query.size();
1585 if (DEBUG_PREFERRED) Log.v(TAG, "Figuring out best match...");
1586 for (int j=0; j<N; j++) {
1587 ResolveInfo ri = query.get(j);
1588 if (DEBUG_PREFERRED) Log.v(TAG, "Match for " + ri.activityInfo
1589 + ": 0x" + Integer.toHexString(match));
1590 if (ri.match > match) match = ri.match;
1591 }
1592 if (DEBUG_PREFERRED) Log.v(TAG, "Best match: 0x"
1593 + Integer.toHexString(match));
1594 match &= IntentFilter.MATCH_CATEGORY_MASK;
1595 final int M = prefs.size();
1596 for (int i=0; i<M; i++) {
1597 PreferredActivity pa = prefs.get(i);
1598 if (pa.mMatch != match) {
1599 continue;
1600 }
1601 ActivityInfo ai = getActivityInfo(pa.mActivity, flags);
1602 if (DEBUG_PREFERRED) {
1603 Log.v(TAG, "Got preferred activity:");
1604 ai.dump(new LogPrinter(Log.INFO, TAG), " ");
1605 }
1606 if (ai != null) {
1607 for (int j=0; j<N; j++) {
1608 ResolveInfo ri = query.get(j);
1609 if (!ri.activityInfo.applicationInfo.packageName
1610 .equals(ai.applicationInfo.packageName)) {
1611 continue;
1612 }
1613 if (!ri.activityInfo.name.equals(ai.name)) {
1614 continue;
1615 }
1616
1617 // Okay we found a previously set preferred app.
1618 // If the result set is different from when this
1619 // was created, we need to clear it and re-ask the
1620 // user their preference.
1621 if (!pa.sameSet(query, priority)) {
1622 Log.i(TAG, "Result set changed, dropping preferred activity for "
1623 + intent + " type " + resolvedType);
1624 mSettings.mPreferredActivities.removeFilter(pa);
1625 return null;
1626 }
1627
1628 // Yay!
1629 return ri;
1630 }
1631 }
1632 }
1633 }
1634 }
1635 return null;
1636 }
1637
1638 public List<ResolveInfo> queryIntentActivities(Intent intent,
1639 String resolvedType, int flags) {
1640 ComponentName comp = intent.getComponent();
1641 if (comp != null) {
1642 List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
1643 ActivityInfo ai = getActivityInfo(comp, flags);
1644 if (ai != null) {
1645 ResolveInfo ri = new ResolveInfo();
1646 ri.activityInfo = ai;
1647 list.add(ri);
1648 }
1649 return list;
1650 }
1651
1652 synchronized (mPackages) {
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07001653 String pkgName = intent.getPackage();
1654 if (pkgName == null) {
1655 return (List<ResolveInfo>)mActivities.queryIntent(intent,
1656 resolvedType, flags);
1657 }
1658 PackageParser.Package pkg = mPackages.get(pkgName);
1659 if (pkg != null) {
1660 return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent,
1661 resolvedType, flags, pkg.activities);
1662 }
1663 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 }
1665 }
1666
1667 public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
1668 Intent[] specifics, String[] specificTypes, Intent intent,
1669 String resolvedType, int flags) {
1670 final String resultsAction = intent.getAction();
1671
1672 List<ResolveInfo> results = queryIntentActivities(
1673 intent, resolvedType, flags|PackageManager.GET_RESOLVED_FILTER);
1674 if (Config.LOGV) Log.v(TAG, "Query " + intent + ": " + results);
1675
1676 int specificsPos = 0;
1677 int N;
1678
1679 // todo: note that the algorithm used here is O(N^2). This
1680 // isn't a problem in our current environment, but if we start running
1681 // into situations where we have more than 5 or 10 matches then this
1682 // should probably be changed to something smarter...
1683
1684 // First we go through and resolve each of the specific items
1685 // that were supplied, taking care of removing any corresponding
1686 // duplicate items in the generic resolve list.
1687 if (specifics != null) {
1688 for (int i=0; i<specifics.length; i++) {
1689 final Intent sintent = specifics[i];
1690 if (sintent == null) {
1691 continue;
1692 }
1693
1694 if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + sintent);
1695 String action = sintent.getAction();
1696 if (resultsAction != null && resultsAction.equals(action)) {
1697 // If this action was explicitly requested, then don't
1698 // remove things that have it.
1699 action = null;
1700 }
1701 ComponentName comp = sintent.getComponent();
1702 ResolveInfo ri = null;
1703 ActivityInfo ai = null;
1704 if (comp == null) {
1705 ri = resolveIntent(
1706 sintent,
1707 specificTypes != null ? specificTypes[i] : null,
1708 flags);
1709 if (ri == null) {
1710 continue;
1711 }
1712 if (ri == mResolveInfo) {
1713 // ACK! Must do something better with this.
1714 }
1715 ai = ri.activityInfo;
1716 comp = new ComponentName(ai.applicationInfo.packageName,
1717 ai.name);
1718 } else {
1719 ai = getActivityInfo(comp, flags);
1720 if (ai == null) {
1721 continue;
1722 }
1723 }
1724
1725 // Look for any generic query activities that are duplicates
1726 // of this specific one, and remove them from the results.
1727 if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + ai);
1728 N = results.size();
1729 int j;
1730 for (j=specificsPos; j<N; j++) {
1731 ResolveInfo sri = results.get(j);
1732 if ((sri.activityInfo.name.equals(comp.getClassName())
1733 && sri.activityInfo.applicationInfo.packageName.equals(
1734 comp.getPackageName()))
1735 || (action != null && sri.filter.matchAction(action))) {
1736 results.remove(j);
1737 if (Config.LOGV) Log.v(
1738 TAG, "Removing duplicate item from " + j
1739 + " due to specific " + specificsPos);
1740 if (ri == null) {
1741 ri = sri;
1742 }
1743 j--;
1744 N--;
1745 }
1746 }
1747
1748 // Add this specific item to its proper place.
1749 if (ri == null) {
1750 ri = new ResolveInfo();
1751 ri.activityInfo = ai;
1752 }
1753 results.add(specificsPos, ri);
1754 ri.specificIndex = i;
1755 specificsPos++;
1756 }
1757 }
1758
1759 // Now we go through the remaining generic results and remove any
1760 // duplicate actions that are found here.
1761 N = results.size();
1762 for (int i=specificsPos; i<N-1; i++) {
1763 final ResolveInfo rii = results.get(i);
1764 if (rii.filter == null) {
1765 continue;
1766 }
1767
1768 // Iterate over all of the actions of this result's intent
1769 // filter... typically this should be just one.
1770 final Iterator<String> it = rii.filter.actionsIterator();
1771 if (it == null) {
1772 continue;
1773 }
1774 while (it.hasNext()) {
1775 final String action = it.next();
1776 if (resultsAction != null && resultsAction.equals(action)) {
1777 // If this action was explicitly requested, then don't
1778 // remove things that have it.
1779 continue;
1780 }
1781 for (int j=i+1; j<N; j++) {
1782 final ResolveInfo rij = results.get(j);
1783 if (rij.filter != null && rij.filter.hasAction(action)) {
1784 results.remove(j);
1785 if (Config.LOGV) Log.v(
1786 TAG, "Removing duplicate item from " + j
1787 + " due to action " + action + " at " + i);
1788 j--;
1789 N--;
1790 }
1791 }
1792 }
1793
1794 // If the caller didn't request filter information, drop it now
1795 // so we don't have to marshall/unmarshall it.
1796 if ((flags&PackageManager.GET_RESOLVED_FILTER) == 0) {
1797 rii.filter = null;
1798 }
1799 }
1800
1801 // Filter out the caller activity if so requested.
1802 if (caller != null) {
1803 N = results.size();
1804 for (int i=0; i<N; i++) {
1805 ActivityInfo ainfo = results.get(i).activityInfo;
1806 if (caller.getPackageName().equals(ainfo.applicationInfo.packageName)
1807 && caller.getClassName().equals(ainfo.name)) {
1808 results.remove(i);
1809 break;
1810 }
1811 }
1812 }
1813
1814 // If the caller didn't request filter information,
1815 // drop them now so we don't have to
1816 // marshall/unmarshall it.
1817 if ((flags&PackageManager.GET_RESOLVED_FILTER) == 0) {
1818 N = results.size();
1819 for (int i=0; i<N; i++) {
1820 results.get(i).filter = null;
1821 }
1822 }
1823
1824 if (Config.LOGV) Log.v(TAG, "Result: " + results);
1825 return results;
1826 }
1827
1828 public List<ResolveInfo> queryIntentReceivers(Intent intent,
1829 String resolvedType, int flags) {
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07001830 ComponentName comp = intent.getComponent();
1831 if (comp != null) {
1832 List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
1833 ActivityInfo ai = getReceiverInfo(comp, flags);
1834 if (ai != null) {
1835 ResolveInfo ri = new ResolveInfo();
1836 ri.activityInfo = ai;
1837 list.add(ri);
1838 }
1839 return list;
1840 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 synchronized (mPackages) {
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07001843 String pkgName = intent.getPackage();
1844 if (pkgName == null) {
1845 return (List<ResolveInfo>)mReceivers.queryIntent(intent,
1846 resolvedType, flags);
1847 }
1848 PackageParser.Package pkg = mPackages.get(pkgName);
1849 if (pkg != null) {
1850 return (List<ResolveInfo>) mReceivers.queryIntentForPackage(intent,
1851 resolvedType, flags, pkg.receivers);
1852 }
1853 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 }
1855 }
1856
1857 public ResolveInfo resolveService(Intent intent, String resolvedType,
1858 int flags) {
1859 List<ResolveInfo> query = queryIntentServices(intent, resolvedType,
1860 flags);
1861 if (query != null) {
1862 if (query.size() >= 1) {
1863 // If there is more than one service with the same priority,
1864 // just arbitrarily pick the first one.
1865 return query.get(0);
1866 }
1867 }
1868 return null;
1869 }
1870
1871 public List<ResolveInfo> queryIntentServices(Intent intent,
1872 String resolvedType, int flags) {
1873 ComponentName comp = intent.getComponent();
1874 if (comp != null) {
1875 List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
1876 ServiceInfo si = getServiceInfo(comp, flags);
1877 if (si != null) {
1878 ResolveInfo ri = new ResolveInfo();
1879 ri.serviceInfo = si;
1880 list.add(ri);
1881 }
1882 return list;
1883 }
1884
1885 synchronized (mPackages) {
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07001886 String pkgName = intent.getPackage();
1887 if (pkgName == null) {
1888 return (List<ResolveInfo>)mServices.queryIntent(intent,
1889 resolvedType, flags);
1890 }
1891 PackageParser.Package pkg = mPackages.get(pkgName);
1892 if (pkg != null) {
1893 return (List<ResolveInfo>)mServices.queryIntentForPackage(intent,
1894 resolvedType, flags, pkg.services);
1895 }
1896 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 }
1898 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001899
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 public List<PackageInfo> getInstalledPackages(int flags) {
1901 ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
1902
1903 synchronized (mPackages) {
1904 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1905 Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
1906 while (i.hasNext()) {
1907 final PackageSetting ps = i.next();
1908 PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags);
1909 if(psPkg != null) {
1910 finalList.add(psPkg);
1911 }
1912 }
1913 }
1914 else {
1915 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1916 while (i.hasNext()) {
1917 final PackageParser.Package p = i.next();
1918 if (p.applicationInfo != null) {
1919 PackageInfo pi = generatePackageInfo(p, flags);
1920 if(pi != null) {
1921 finalList.add(pi);
1922 }
1923 }
1924 }
1925 }
1926 }
1927 return finalList;
1928 }
1929
1930 public List<ApplicationInfo> getInstalledApplications(int flags) {
1931 ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
1932 synchronized(mPackages) {
1933 if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
1934 Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
1935 while (i.hasNext()) {
1936 final PackageSetting ps = i.next();
1937 ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags);
1938 if(ai != null) {
1939 finalList.add(ai);
1940 }
1941 }
1942 }
1943 else {
1944 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1945 while (i.hasNext()) {
1946 final PackageParser.Package p = i.next();
1947 if (p.applicationInfo != null) {
1948 ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags);
1949 if(ai != null) {
1950 finalList.add(ai);
1951 }
1952 }
1953 }
1954 }
1955 }
1956 return finalList;
1957 }
1958
1959 public List<ApplicationInfo> getPersistentApplications(int flags) {
1960 ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
1961
1962 synchronized (mPackages) {
1963 Iterator<PackageParser.Package> i = mPackages.values().iterator();
1964 while (i.hasNext()) {
1965 PackageParser.Package p = i.next();
1966 if (p.applicationInfo != null
1967 && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
1968 && (!mSafeMode || (p.applicationInfo.flags
1969 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
1970 finalList.add(p.applicationInfo);
1971 }
1972 }
1973 }
1974
1975 return finalList;
1976 }
1977
1978 public ProviderInfo resolveContentProvider(String name, int flags) {
1979 synchronized (mPackages) {
1980 final PackageParser.Provider provider = mProviders.get(name);
1981 return provider != null
1982 && mSettings.isEnabledLP(provider.info, flags)
1983 && (!mSafeMode || (provider.info.applicationInfo.flags
1984 &ApplicationInfo.FLAG_SYSTEM) != 0)
1985 ? PackageParser.generateProviderInfo(provider, flags)
1986 : null;
1987 }
1988 }
1989
Fred Quintana718d8a22009-04-29 17:53:20 -07001990 /**
1991 * @deprecated
1992 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 public void querySyncProviders(List outNames, List outInfo) {
1994 synchronized (mPackages) {
1995 Iterator<Map.Entry<String, PackageParser.Provider>> i
1996 = mProviders.entrySet().iterator();
1997
1998 while (i.hasNext()) {
1999 Map.Entry<String, PackageParser.Provider> entry = i.next();
2000 PackageParser.Provider p = entry.getValue();
2001
2002 if (p.syncable
2003 && (!mSafeMode || (p.info.applicationInfo.flags
2004 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
2005 outNames.add(entry.getKey());
2006 outInfo.add(PackageParser.generateProviderInfo(p, 0));
2007 }
2008 }
2009 }
2010 }
2011
2012 public List<ProviderInfo> queryContentProviders(String processName,
2013 int uid, int flags) {
2014 ArrayList<ProviderInfo> finalList = null;
2015
2016 synchronized (mPackages) {
2017 Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
2018 while (i.hasNext()) {
2019 PackageParser.Provider p = i.next();
2020 if (p.info.authority != null
2021 && (processName == null ||
2022 (p.info.processName.equals(processName)
2023 && p.info.applicationInfo.uid == uid))
2024 && mSettings.isEnabledLP(p.info, flags)
2025 && (!mSafeMode || (p.info.applicationInfo.flags
2026 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
2027 if (finalList == null) {
2028 finalList = new ArrayList<ProviderInfo>(3);
2029 }
2030 finalList.add(PackageParser.generateProviderInfo(p,
2031 flags));
2032 }
2033 }
2034 }
2035
2036 if (finalList != null) {
2037 Collections.sort(finalList, mProviderInitOrderSorter);
2038 }
2039
2040 return finalList;
2041 }
2042
2043 public InstrumentationInfo getInstrumentationInfo(ComponentName name,
2044 int flags) {
2045 synchronized (mPackages) {
2046 final PackageParser.Instrumentation i = mInstrumentation.get(name);
2047 return PackageParser.generateInstrumentationInfo(i, flags);
2048 }
2049 }
2050
2051 public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
2052 int flags) {
2053 ArrayList<InstrumentationInfo> finalList =
2054 new ArrayList<InstrumentationInfo>();
2055
2056 synchronized (mPackages) {
2057 Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
2058 while (i.hasNext()) {
2059 PackageParser.Instrumentation p = i.next();
2060 if (targetPackage == null
2061 || targetPackage.equals(p.info.targetPackage)) {
2062 finalList.add(PackageParser.generateInstrumentationInfo(p,
2063 flags));
2064 }
2065 }
2066 }
2067
2068 return finalList;
2069 }
2070
2071 private void scanDirLI(File dir, int flags, int scanMode) {
2072 Log.d(TAG, "Scanning app dir " + dir);
2073
2074 String[] files = dir.list();
2075
2076 int i;
2077 for (i=0; i<files.length; i++) {
2078 File file = new File(dir, files[i]);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002079 PackageParser.Package pkg = scanPackageLI(file,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002080 flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
2081 }
2082 }
2083
2084 private static void reportSettingsProblem(int priority, String msg) {
2085 try {
2086 File dataDir = Environment.getDataDirectory();
2087 File systemDir = new File(dataDir, "system");
2088 File fname = new File(systemDir, "uiderrors.txt");
2089 FileOutputStream out = new FileOutputStream(fname, true);
2090 PrintWriter pw = new PrintWriter(out);
2091 pw.println(msg);
2092 pw.close();
2093 FileUtils.setPermissions(
2094 fname.toString(),
2095 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
2096 -1, -1);
2097 } catch (java.io.IOException e) {
2098 }
2099 Log.println(priority, TAG, msg);
2100 }
2101
2102 private boolean collectCertificatesLI(PackageParser pp, PackageSetting ps,
2103 PackageParser.Package pkg, File srcFile, int parseFlags) {
2104 if (GET_CERTIFICATES) {
2105 if (ps == null || !ps.codePath.equals(srcFile)
2106 || ps.getTimeStamp() != srcFile.lastModified()) {
2107 Log.i(TAG, srcFile.toString() + " changed; collecting certs");
2108 if (!pp.collectCertificates(pkg, parseFlags)) {
2109 mLastScanError = pp.getParseError();
2110 return false;
2111 }
2112 }
2113 }
2114 return true;
2115 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 /*
2118 * Scan a package and return the newly parsed package.
2119 * Returns null in case of errors and the error code is stored in mLastScanError
2120 */
2121 private PackageParser.Package scanPackageLI(File scanFile,
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002122 int parseFlags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123 int scanMode) {
2124 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002125 String scanPath = scanFile.getPath();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002126 parseFlags |= mDefParseFlags;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002127 PackageParser pp = new PackageParser(scanPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002128 pp.setSeparateProcesses(mSeparateProcesses);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 final PackageParser.Package pkg = pp.parsePackage(scanFile,
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002130 scanPath,
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002131 mMetrics, parseFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 if (pkg == null) {
2133 mLastScanError = pp.getParseError();
2134 return null;
2135 }
2136 PackageSetting ps;
2137 PackageSetting updatedPkg;
2138 synchronized (mPackages) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07002139 ps = mSettings.peekPackageLP(pkg.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140 updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName);
2141 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07002142 // Verify certificates first
2143 if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
2144 Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
2145 return null;
2146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147 if (updatedPkg != null) {
2148 // An updated system app will not have the PARSE_IS_SYSTEM flag set initially
2149 parseFlags |= PackageParser.PARSE_IS_SYSTEM;
2150 }
2151 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
2152 // Check for updated system applications here
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002153 if ((ps != null) && (!ps.codePath.equals(scanFile))) {
2154 if (pkg.mVersionCode < ps.versionCode) {
2155 // The system package has been updated and the code path does not match
2156 // Ignore entry. Just return
2157 Log.w(TAG, "Package:" + pkg.packageName +
2158 " has been updated. Ignoring the one from path:"+scanFile);
2159 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
2160 return null;
2161 } else {
2162 // Delete the older apk pointed to by ps
2163 // At this point, its safely assumed that package installation for
2164 // apps in system partition will go through. If not there won't be a working
2165 // version of the app
2166 synchronized (mPackages) {
2167 // Just remove the loaded entries from package lists.
2168 mPackages.remove(ps.name);
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07002169 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002170 InstallArgs args = new FileInstallArgs(ps.codePathString, ps.resourcePathString);
2171 args.cleanUpResourcesLI();
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002172 mSettings.enableSystemPackageLP(ps.name);
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07002173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 }
2175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002176 // The apk is forward locked (not public) if its code and resources
2177 // are kept in different files.
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002178 // TODO grab this value from PackageSettings
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002180 parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
Suchi Amalapurapuf2c10722009-07-29 17:19:39 -07002181 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002182
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002183 String codePath = null;
2184 String resPath = null;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002185 if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) {
2186 if (ps != null && ps.resourcePathString != null) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002187 resPath = ps.resourcePathString;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002188 } else {
2189 // Should not happen at all. Just log an error.
2190 Log.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
2191 }
2192 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002193 resPath = pkg.mScanPath;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002194 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002195 codePath = pkg.mScanPath;
2196 // Set application objects path explicitly.
2197 setApplicationInfoPaths(pkg, codePath, resPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198 // Note that we invoke the following method only if we are about to unpack an application
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002199 return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 }
2201
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002202 private static void setApplicationInfoPaths(PackageParser.Package pkg,
2203 String destCodePath, String destResPath) {
2204 pkg.mPath = pkg.mScanPath = destCodePath;
2205 pkg.applicationInfo.sourceDir = destCodePath;
2206 pkg.applicationInfo.publicSourceDir = destResPath;
2207 }
2208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 private static String fixProcessName(String defProcessName,
2210 String processName, int uid) {
2211 if (processName == null) {
2212 return defProcessName;
2213 }
2214 return processName;
2215 }
2216
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002217 private boolean verifySignaturesLP(PackageSetting pkgSetting,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002218 PackageParser.Package pkg, int parseFlags, boolean updateSignature) {
2219 if (pkg.mSignatures != null) {
2220 if (!pkgSetting.signatures.updateSignatures(pkg.mSignatures,
2221 updateSignature)) {
2222 Log.e(TAG, "Package " + pkg.packageName
2223 + " signatures do not match the previously installed version; ignoring!");
2224 mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
2225 return false;
2226 }
2227
2228 if (pkgSetting.sharedUser != null) {
2229 if (!pkgSetting.sharedUser.signatures.mergeSignatures(
2230 pkg.mSignatures, updateSignature)) {
2231 Log.e(TAG, "Package " + pkg.packageName
2232 + " has no signatures that match those in shared user "
2233 + pkgSetting.sharedUser.name + "; ignoring!");
2234 mLastScanError = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
2235 return false;
2236 }
2237 }
2238 } else {
2239 pkg.mSignatures = pkgSetting.signatures.mSignatures;
2240 }
2241 return true;
2242 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002243
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002244 public boolean performDexOpt(String packageName) {
2245 if (!mNoDexOpt) {
2246 return false;
2247 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002248
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002249 PackageParser.Package p;
2250 synchronized (mPackages) {
2251 p = mPackages.get(packageName);
2252 if (p == null || p.mDidDexOpt) {
2253 return false;
2254 }
2255 }
2256 synchronized (mInstallLock) {
2257 return performDexOptLI(p, false) == DEX_OPT_PERFORMED;
2258 }
2259 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002260
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002261 static final int DEX_OPT_SKIPPED = 0;
2262 static final int DEX_OPT_PERFORMED = 1;
2263 static final int DEX_OPT_FAILED = -1;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002264
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002265 private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
2266 boolean performed = false;
Marco Nelissend595c792009-07-02 15:23:26 -07002267 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0 && mInstaller != null) {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002268 String path = pkg.mScanPath;
2269 int ret = 0;
2270 try {
2271 if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002272 ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002273 !isForwardLocked(pkg));
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002274 pkg.mDidDexOpt = true;
2275 performed = true;
2276 }
2277 } catch (FileNotFoundException e) {
2278 Log.w(TAG, "Apk not found for dexopt: " + path);
2279 ret = -1;
2280 } catch (IOException e) {
2281 Log.w(TAG, "Exception reading apk: " + path, e);
2282 ret = -1;
2283 }
2284 if (ret < 0) {
2285 //error from installer
2286 return DEX_OPT_FAILED;
2287 }
2288 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002289
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002290 return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
2291 }
Oscar Montemayora8529f62009-11-18 10:14:20 -08002292
2293 private static boolean useEncryptedFilesystemForPackage(PackageParser.Package pkg) {
2294 return Environment.isEncryptedFilesystemEnabled() &&
2295 ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_NEVER_ENCRYPT) == 0);
2296 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002298 private PackageParser.Package scanPackageLI(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002299 PackageParser.Package pkg, int parseFlags, int scanMode) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002300 File scanFile = new File(pkg.mScanPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002301 mScanningPath = scanFile;
2302 if (pkg == null) {
2303 mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
2304 return null;
2305 }
2306
2307 final String pkgName = pkg.applicationInfo.packageName;
2308 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
2309 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
2310 }
2311
2312 if (pkgName.equals("android")) {
2313 synchronized (mPackages) {
2314 if (mAndroidApplication != null) {
2315 Log.w(TAG, "*************************************************");
2316 Log.w(TAG, "Core android package being redefined. Skipping.");
2317 Log.w(TAG, " file=" + mScanningPath);
2318 Log.w(TAG, "*************************************************");
2319 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
2320 return null;
2321 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002323 // Set up information for our fall-back user intent resolution
2324 // activity.
2325 mPlatformPackage = pkg;
2326 pkg.mVersionCode = mSdkVersion;
2327 mAndroidApplication = pkg.applicationInfo;
2328 mResolveActivity.applicationInfo = mAndroidApplication;
2329 mResolveActivity.name = ResolverActivity.class.getName();
2330 mResolveActivity.packageName = mAndroidApplication.packageName;
2331 mResolveActivity.processName = mAndroidApplication.processName;
2332 mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
2333 mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
2334 mResolveActivity.theme = com.android.internal.R.style.Theme_Dialog_Alert;
2335 mResolveActivity.exported = true;
2336 mResolveActivity.enabled = true;
2337 mResolveInfo.activityInfo = mResolveActivity;
2338 mResolveInfo.priority = 0;
2339 mResolveInfo.preferredOrder = 0;
2340 mResolveInfo.match = 0;
2341 mResolveComponentName = new ComponentName(
2342 mAndroidApplication.packageName, mResolveActivity.name);
2343 }
2344 }
2345
2346 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
2347 TAG, "Scanning package " + pkgName);
2348 if (mPackages.containsKey(pkgName) || mSharedLibraries.containsKey(pkgName)) {
2349 Log.w(TAG, "*************************************************");
2350 Log.w(TAG, "Application package " + pkgName
2351 + " already installed. Skipping duplicate.");
2352 Log.w(TAG, "*************************************************");
2353 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
2354 return null;
2355 }
2356
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002357 // Initialize package source and resource directories
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002358 File destCodeFile = new File(pkg.applicationInfo.sourceDir);
2359 File destResourceFile = new File(pkg.applicationInfo.publicSourceDir);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 SharedUserSetting suid = null;
2362 PackageSetting pkgSetting = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002364 boolean removeExisting = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002366 synchronized (mPackages) {
2367 // Check all shared libraries and map to their actual file path.
Dianne Hackborn49237342009-08-27 20:08:01 -07002368 if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
2369 if (mTmpSharedLibraries == null ||
2370 mTmpSharedLibraries.length < mSharedLibraries.size()) {
2371 mTmpSharedLibraries = new String[mSharedLibraries.size()];
2372 }
2373 int num = 0;
2374 int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
2375 for (int i=0; i<N; i++) {
2376 String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002377 if (file == null) {
2378 Log.e(TAG, "Package " + pkg.packageName
2379 + " requires unavailable shared library "
Dianne Hackborn49237342009-08-27 20:08:01 -07002380 + pkg.usesLibraries.get(i) + "; failing!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002381 mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
2382 return null;
2383 }
Dianne Hackborn49237342009-08-27 20:08:01 -07002384 mTmpSharedLibraries[num] = file;
2385 num++;
2386 }
2387 N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
2388 for (int i=0; i<N; i++) {
2389 String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
2390 if (file == null) {
2391 Log.w(TAG, "Package " + pkg.packageName
2392 + " desires unavailable shared library "
2393 + pkg.usesOptionalLibraries.get(i) + "; ignoring!");
2394 } else {
2395 mTmpSharedLibraries[num] = file;
2396 num++;
2397 }
2398 }
2399 if (num > 0) {
2400 pkg.usesLibraryFiles = new String[num];
2401 System.arraycopy(mTmpSharedLibraries, 0,
2402 pkg.usesLibraryFiles, 0, num);
2403 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002404
Dianne Hackborn49237342009-08-27 20:08:01 -07002405 if (pkg.reqFeatures != null) {
2406 N = pkg.reqFeatures.size();
2407 for (int i=0; i<N; i++) {
2408 FeatureInfo fi = pkg.reqFeatures.get(i);
2409 if ((fi.flags&FeatureInfo.FLAG_REQUIRED) == 0) {
2410 // Don't care.
2411 continue;
2412 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002413
Dianne Hackborn49237342009-08-27 20:08:01 -07002414 if (fi.name != null) {
2415 if (mAvailableFeatures.get(fi.name) == null) {
2416 Log.e(TAG, "Package " + pkg.packageName
2417 + " requires unavailable feature "
2418 + fi.name + "; failing!");
2419 mLastScanError = PackageManager.INSTALL_FAILED_MISSING_FEATURE;
2420 return null;
2421 }
2422 }
2423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002424 }
2425 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002427 if (pkg.mSharedUserId != null) {
2428 suid = mSettings.getSharedUserLP(pkg.mSharedUserId,
2429 pkg.applicationInfo.flags, true);
2430 if (suid == null) {
2431 Log.w(TAG, "Creating application package " + pkgName
2432 + " for shared user failed");
2433 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2434 return null;
2435 }
2436 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) {
2437 Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid="
2438 + suid.userId + "): packages=" + suid.packages);
2439 }
2440 }
Suchi Amalapurapuea5c0442009-07-13 10:36:15 -07002441
2442 // Just create the setting, don't add it yet. For already existing packages
2443 // the PkgSetting exists already and doesn't have to be created.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002444 pkgSetting = mSettings.getPackageLP(pkg, suid, destCodeFile,
2445 destResourceFile, pkg.applicationInfo.flags, true, false);
2446 if (pkgSetting == null) {
2447 Log.w(TAG, "Creating application package " + pkgName + " failed");
2448 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2449 return null;
2450 }
2451 if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
2452 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
2453 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002455 pkg.applicationInfo.uid = pkgSetting.userId;
2456 pkg.mExtras = pkgSetting;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002457
2458 if (!verifySignaturesLP(pkgSetting, pkg, parseFlags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459 (scanMode&SCAN_UPDATE_SIGNATURE) != 0)) {
2460 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) {
2461 mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
2462 return null;
2463 }
2464 // The signature has changed, but this package is in the system
2465 // image... let's recover!
Suchi Amalapurapuc4dd60f2009-03-24 21:10:53 -07002466 pkgSetting.signatures.mSignatures = pkg.mSignatures;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002467 // However... if this package is part of a shared user, but it
2468 // doesn't match the signature of the shared user, let's fail.
2469 // What this means is that you can't change the signatures
2470 // associated with an overall shared user, which doesn't seem all
2471 // that unreasonable.
2472 if (pkgSetting.sharedUser != null) {
2473 if (!pkgSetting.sharedUser.signatures.mergeSignatures(
2474 pkg.mSignatures, false)) {
2475 mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
2476 return null;
2477 }
2478 }
2479 removeExisting = true;
2480 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002481
The Android Open Source Project10592532009-03-18 17:39:46 -07002482 // Verify that this new package doesn't have any content providers
2483 // that conflict with existing packages. Only do this if the
2484 // package isn't already installed, since we don't want to break
2485 // things that are installed.
2486 if ((scanMode&SCAN_NEW_INSTALL) != 0) {
2487 int N = pkg.providers.size();
2488 int i;
2489 for (i=0; i<N; i++) {
2490 PackageParser.Provider p = pkg.providers.get(i);
2491 String names[] = p.info.authority.split(";");
2492 for (int j = 0; j < names.length; j++) {
2493 if (mProviders.containsKey(names[j])) {
2494 PackageParser.Provider other = mProviders.get(names[j]);
2495 Log.w(TAG, "Can't install because provider name " + names[j] +
2496 " (in package " + pkg.applicationInfo.packageName +
2497 ") is already used by "
2498 + ((other != null && other.component != null)
2499 ? other.component.getPackageName() : "?"));
2500 mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
2501 return null;
2502 }
2503 }
2504 }
2505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002506 }
2507
2508 if (removeExisting) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08002509 boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002510 if (mInstaller != null) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08002511 int ret = mInstaller.remove(pkgName, useEncryptedFSDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002512 if (ret != 0) {
2513 String msg = "System package " + pkg.packageName
2514 + " could not have data directory erased after signature change.";
2515 reportSettingsProblem(Log.WARN, msg);
2516 mLastScanError = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
2517 return null;
2518 }
2519 }
2520 Log.w(TAG, "System package " + pkg.packageName
2521 + " signature changed: existing data removed.");
2522 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
2523 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002525 long scanFileTime = scanFile.lastModified();
2526 final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
2527 final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp();
2528 pkg.applicationInfo.processName = fixProcessName(
2529 pkg.applicationInfo.packageName,
2530 pkg.applicationInfo.processName,
2531 pkg.applicationInfo.uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002532
2533 File dataPath;
2534 if (mPlatformPackage == pkg) {
2535 // The system package is special.
2536 dataPath = new File (Environment.getDataDirectory(), "system");
2537 pkg.applicationInfo.dataDir = dataPath.getPath();
2538 } else {
2539 // This is a normal package, need to make its data directory.
Oscar Montemayora8529f62009-11-18 10:14:20 -08002540 boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg);
2541 if (useEncryptedFSDir) {
2542 dataPath = new File(mSecureAppDataDir, pkgName);
2543 } else {
2544 dataPath = new File(mAppDataDir, pkgName);
2545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 if (dataPath.exists()) {
2547 mOutPermissions[1] = 0;
2548 FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
2549 if (mOutPermissions[1] == pkg.applicationInfo.uid
2550 || !Process.supportsProcesses()) {
2551 pkg.applicationInfo.dataDir = dataPath.getPath();
2552 } else {
2553 boolean recovered = false;
2554 if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
2555 // If this is a system app, we can at least delete its
2556 // current data so the application will still work.
2557 if (mInstaller != null) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08002558 int ret = mInstaller.remove(pkgName, useEncryptedFSDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002559 if(ret >= 0) {
2560 // Old data gone!
2561 String msg = "System package " + pkg.packageName
2562 + " has changed from uid: "
2563 + mOutPermissions[1] + " to "
2564 + pkg.applicationInfo.uid + "; old data erased";
2565 reportSettingsProblem(Log.WARN, msg);
2566 recovered = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002568 // And now re-install the app.
Oscar Montemayora8529f62009-11-18 10:14:20 -08002569 ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 pkg.applicationInfo.uid);
2571 if (ret == -1) {
2572 // Ack should not happen!
2573 msg = "System package " + pkg.packageName
2574 + " could not have data directory re-created after delete.";
2575 reportSettingsProblem(Log.WARN, msg);
2576 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2577 return null;
2578 }
2579 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002581 if (!recovered) {
2582 mHasSystemUidErrors = true;
2583 }
2584 }
2585 if (!recovered) {
2586 pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
2587 + pkg.applicationInfo.uid + "/fs_"
2588 + mOutPermissions[1];
2589 String msg = "Package " + pkg.packageName
2590 + " has mismatched uid: "
2591 + mOutPermissions[1] + " on disk, "
2592 + pkg.applicationInfo.uid + " in settings";
2593 synchronized (mPackages) {
2594 if (!mReportedUidError) {
2595 mReportedUidError = true;
2596 msg = msg + "; read messages:\n"
2597 + mSettings.getReadMessagesLP();
2598 }
2599 reportSettingsProblem(Log.ERROR, msg);
2600 }
2601 }
2602 }
2603 pkg.applicationInfo.dataDir = dataPath.getPath();
2604 } else {
2605 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGV)
2606 Log.v(TAG, "Want this data dir: " + dataPath);
2607 //invoke installer to do the actual installation
2608 if (mInstaller != null) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08002609 int ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002610 pkg.applicationInfo.uid);
2611 if(ret < 0) {
2612 // Error from installer
2613 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2614 return null;
2615 }
2616 } else {
2617 dataPath.mkdirs();
2618 if (dataPath.exists()) {
2619 FileUtils.setPermissions(
2620 dataPath.toString(),
2621 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
2622 pkg.applicationInfo.uid, pkg.applicationInfo.uid);
2623 }
2624 }
2625 if (dataPath.exists()) {
2626 pkg.applicationInfo.dataDir = dataPath.getPath();
2627 } else {
2628 Log.w(TAG, "Unable to create data directory: " + dataPath);
2629 pkg.applicationInfo.dataDir = null;
2630 }
2631 }
2632 }
2633
2634 // Perform shared library installation and dex validation and
2635 // optimization, if this is not a system app.
2636 if (mInstaller != null) {
2637 String path = scanFile.getPath();
2638 if (scanFileNewer) {
2639 Log.i(TAG, path + " changed; unpacking");
Dianne Hackbornb1811182009-05-21 15:45:42 -07002640 int err = cachePackageSharedLibsLI(pkg, dataPath, scanFile);
2641 if (err != PackageManager.INSTALL_SUCCEEDED) {
2642 mLastScanError = err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 return null;
2644 }
2645 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002646 pkg.mScanPath = path;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002647
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002648 if ((scanMode&SCAN_NO_DEX) == 0) {
2649 if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002650 mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
2651 return null;
2652 }
2653 }
2654 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002655
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002656 if (mFactoryTest && pkg.requestedPermissions.contains(
2657 android.Manifest.permission.FACTORY_TEST)) {
2658 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
2659 }
2660
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07002661 // We don't expect installation to fail beyond this point,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662 if ((scanMode&SCAN_MONITOR) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002663 mAppDirs.put(pkg.mPath, pkg);
2664 }
2665
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07002666 // Request the ActivityManager to kill the process(only for existing packages)
2667 // so that we do not end up in a confused state while the user is still using the older
2668 // version of the application while the new one gets installed.
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002669 if ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING ) != 0) {
2670 killApplication(pkg.applicationInfo.packageName,
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07002671 pkg.applicationInfo.uid);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07002672 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674 synchronized (mPackages) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 // Add the new setting to mSettings
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08002676 mSettings.insertPackageSettingLP(pkgSetting, pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002677 // Add the new setting to mPackages
Suchi Amalapurapuea5c0442009-07-13 10:36:15 -07002678 mPackages.put(pkg.applicationInfo.packageName, pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002679 int N = pkg.providers.size();
2680 StringBuilder r = null;
2681 int i;
2682 for (i=0; i<N; i++) {
2683 PackageParser.Provider p = pkg.providers.get(i);
2684 p.info.processName = fixProcessName(pkg.applicationInfo.processName,
2685 p.info.processName, pkg.applicationInfo.uid);
2686 mProvidersByComponent.put(new ComponentName(p.info.packageName,
2687 p.info.name), p);
2688 p.syncable = p.info.isSyncable;
2689 String names[] = p.info.authority.split(";");
2690 p.info.authority = null;
2691 for (int j = 0; j < names.length; j++) {
2692 if (j == 1 && p.syncable) {
2693 // We only want the first authority for a provider to possibly be
2694 // syncable, so if we already added this provider using a different
2695 // authority clear the syncable flag. We copy the provider before
2696 // changing it because the mProviders object contains a reference
2697 // to a provider that we don't want to change.
2698 // Only do this for the second authority since the resulting provider
2699 // object can be the same for all future authorities for this provider.
2700 p = new PackageParser.Provider(p);
2701 p.syncable = false;
2702 }
2703 if (!mProviders.containsKey(names[j])) {
2704 mProviders.put(names[j], p);
2705 if (p.info.authority == null) {
2706 p.info.authority = names[j];
2707 } else {
2708 p.info.authority = p.info.authority + ";" + names[j];
2709 }
2710 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD)
2711 Log.d(TAG, "Registered content provider: " + names[j] +
2712 ", className = " + p.info.name +
2713 ", isSyncable = " + p.info.isSyncable);
2714 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07002715 PackageParser.Provider other = mProviders.get(names[j]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002716 Log.w(TAG, "Skipping provider name " + names[j] +
2717 " (in package " + pkg.applicationInfo.packageName +
The Android Open Source Project10592532009-03-18 17:39:46 -07002718 "): name already used by "
2719 + ((other != null && other.component != null)
2720 ? other.component.getPackageName() : "?"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002721 }
2722 }
2723 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2724 if (r == null) {
2725 r = new StringBuilder(256);
2726 } else {
2727 r.append(' ');
2728 }
2729 r.append(p.info.name);
2730 }
2731 }
2732 if (r != null) {
2733 if (Config.LOGD) Log.d(TAG, " Providers: " + r);
2734 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002736 N = pkg.services.size();
2737 r = null;
2738 for (i=0; i<N; i++) {
2739 PackageParser.Service s = pkg.services.get(i);
2740 s.info.processName = fixProcessName(pkg.applicationInfo.processName,
2741 s.info.processName, pkg.applicationInfo.uid);
2742 mServices.addService(s);
2743 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2744 if (r == null) {
2745 r = new StringBuilder(256);
2746 } else {
2747 r.append(' ');
2748 }
2749 r.append(s.info.name);
2750 }
2751 }
2752 if (r != null) {
2753 if (Config.LOGD) Log.d(TAG, " Services: " + r);
2754 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002756 N = pkg.receivers.size();
2757 r = null;
2758 for (i=0; i<N; i++) {
2759 PackageParser.Activity a = pkg.receivers.get(i);
2760 a.info.processName = fixProcessName(pkg.applicationInfo.processName,
2761 a.info.processName, pkg.applicationInfo.uid);
2762 mReceivers.addActivity(a, "receiver");
2763 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2764 if (r == null) {
2765 r = new StringBuilder(256);
2766 } else {
2767 r.append(' ');
2768 }
2769 r.append(a.info.name);
2770 }
2771 }
2772 if (r != null) {
2773 if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
2774 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002776 N = pkg.activities.size();
2777 r = null;
2778 for (i=0; i<N; i++) {
2779 PackageParser.Activity a = pkg.activities.get(i);
2780 a.info.processName = fixProcessName(pkg.applicationInfo.processName,
2781 a.info.processName, pkg.applicationInfo.uid);
2782 mActivities.addActivity(a, "activity");
2783 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2784 if (r == null) {
2785 r = new StringBuilder(256);
2786 } else {
2787 r.append(' ');
2788 }
2789 r.append(a.info.name);
2790 }
2791 }
2792 if (r != null) {
2793 if (Config.LOGD) Log.d(TAG, " Activities: " + r);
2794 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002796 N = pkg.permissionGroups.size();
2797 r = null;
2798 for (i=0; i<N; i++) {
2799 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
2800 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
2801 if (cur == null) {
2802 mPermissionGroups.put(pg.info.name, pg);
2803 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2804 if (r == null) {
2805 r = new StringBuilder(256);
2806 } else {
2807 r.append(' ');
2808 }
2809 r.append(pg.info.name);
2810 }
2811 } else {
2812 Log.w(TAG, "Permission group " + pg.info.name + " from package "
2813 + pg.info.packageName + " ignored: original from "
2814 + cur.info.packageName);
2815 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2816 if (r == null) {
2817 r = new StringBuilder(256);
2818 } else {
2819 r.append(' ');
2820 }
2821 r.append("DUP:");
2822 r.append(pg.info.name);
2823 }
2824 }
2825 }
2826 if (r != null) {
2827 if (Config.LOGD) Log.d(TAG, " Permission Groups: " + r);
2828 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002830 N = pkg.permissions.size();
2831 r = null;
2832 for (i=0; i<N; i++) {
2833 PackageParser.Permission p = pkg.permissions.get(i);
2834 HashMap<String, BasePermission> permissionMap =
2835 p.tree ? mSettings.mPermissionTrees
2836 : mSettings.mPermissions;
2837 p.group = mPermissionGroups.get(p.info.group);
2838 if (p.info.group == null || p.group != null) {
2839 BasePermission bp = permissionMap.get(p.info.name);
2840 if (bp == null) {
2841 bp = new BasePermission(p.info.name, p.info.packageName,
2842 BasePermission.TYPE_NORMAL);
2843 permissionMap.put(p.info.name, bp);
2844 }
2845 if (bp.perm == null) {
2846 if (bp.sourcePackage == null
2847 || bp.sourcePackage.equals(p.info.packageName)) {
2848 BasePermission tree = findPermissionTreeLP(p.info.name);
2849 if (tree == null
2850 || tree.sourcePackage.equals(p.info.packageName)) {
2851 bp.perm = p;
2852 bp.uid = pkg.applicationInfo.uid;
2853 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2854 if (r == null) {
2855 r = new StringBuilder(256);
2856 } else {
2857 r.append(' ');
2858 }
2859 r.append(p.info.name);
2860 }
2861 } else {
2862 Log.w(TAG, "Permission " + p.info.name + " from package "
2863 + p.info.packageName + " ignored: base tree "
2864 + tree.name + " is from package "
2865 + tree.sourcePackage);
2866 }
2867 } else {
2868 Log.w(TAG, "Permission " + p.info.name + " from package "
2869 + p.info.packageName + " ignored: original from "
2870 + bp.sourcePackage);
2871 }
2872 } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2873 if (r == null) {
2874 r = new StringBuilder(256);
2875 } else {
2876 r.append(' ');
2877 }
2878 r.append("DUP:");
2879 r.append(p.info.name);
2880 }
2881 } else {
2882 Log.w(TAG, "Permission " + p.info.name + " from package "
2883 + p.info.packageName + " ignored: no group "
2884 + p.group);
2885 }
2886 }
2887 if (r != null) {
2888 if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
2889 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002891 N = pkg.instrumentation.size();
2892 r = null;
2893 for (i=0; i<N; i++) {
2894 PackageParser.Instrumentation a = pkg.instrumentation.get(i);
2895 a.info.packageName = pkg.applicationInfo.packageName;
2896 a.info.sourceDir = pkg.applicationInfo.sourceDir;
2897 a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
2898 a.info.dataDir = pkg.applicationInfo.dataDir;
2899 mInstrumentation.put(a.component, a);
2900 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
2901 if (r == null) {
2902 r = new StringBuilder(256);
2903 } else {
2904 r.append(' ');
2905 }
2906 r.append(a.info.name);
2907 }
2908 }
2909 if (r != null) {
2910 if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
2911 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002912
Dianne Hackborn854060af2009-07-09 18:14:31 -07002913 if (pkg.protectedBroadcasts != null) {
2914 N = pkg.protectedBroadcasts.size();
2915 for (i=0; i<N; i++) {
2916 mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
2917 }
2918 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 pkgSetting.setTimeStamp(scanFileTime);
2921 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 return pkg;
2924 }
2925
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08002926 private void killApplication(String pkgName, int uid) {
2927 // Request the ActivityManager to kill the process(only for existing packages)
2928 // so that we do not end up in a confused state while the user is still using the older
2929 // version of the application while the new one gets installed.
2930 IActivityManager am = ActivityManagerNative.getDefault();
2931 if (am != null) {
2932 try {
2933 am.killApplicationWithUid(pkgName, uid);
2934 } catch (RemoteException e) {
2935 }
2936 }
2937 }
2938
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08002939 // The following constants are returned by cachePackageSharedLibsForAbiLI
2940 // to indicate if native shared libraries were found in the package.
2941 // Values are:
2942 // PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed
2943 // PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package
2944 // PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found
2945 // in package (and not installed)
2946 //
2947 private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0;
2948 private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1;
2949 private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002950
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08002951 // Find all files of the form lib/<cpuAbi>/lib<name>.so in the .apk
2952 // and automatically copy them to /data/data/<appname>/lib if present.
2953 //
2954 // NOTE: this method may throw an IOException if the library cannot
2955 // be copied to its final destination, e.g. if there isn't enough
2956 // room left on the data partition, or a ZipException if the package
2957 // file is malformed.
2958 //
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08002959 private int cachePackageSharedLibsForAbiLI(PackageParser.Package pkg,
2960 File dataPath, File scanFile, String cpuAbi) throws IOException, ZipException {
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08002961 File sharedLibraryDir = new File(dataPath.getPath() + "/lib");
2962 final String apkLib = "lib/";
2963 final int apkLibLen = apkLib.length();
2964 final int cpuAbiLen = cpuAbi.length();
2965 final String libPrefix = "lib";
2966 final int libPrefixLen = libPrefix.length();
2967 final String libSuffix = ".so";
2968 final int libSuffixLen = libSuffix.length();
2969 boolean hasNativeLibraries = false;
2970 boolean installedNativeLibraries = false;
2971
2972 // the minimum length of a valid native shared library of the form
2973 // lib/<something>/lib<name>.so.
2974 final int minEntryLen = apkLibLen + 2 + libPrefixLen + 1 + libSuffixLen;
2975
2976 ZipFile zipFile = new ZipFile(scanFile);
2977 Enumeration<ZipEntry> entries =
2978 (Enumeration<ZipEntry>) zipFile.entries();
2979
2980 while (entries.hasMoreElements()) {
2981 ZipEntry entry = entries.nextElement();
2982 // skip directories
2983 if (entry.isDirectory()) {
2984 continue;
2985 }
2986 String entryName = entry.getName();
2987
2988 // check that the entry looks like lib/<something>/lib<name>.so
2989 // here, but don't check the ABI just yet.
2990 //
2991 // - must be sufficiently long
2992 // - must end with libSuffix, i.e. ".so"
2993 // - must start with apkLib, i.e. "lib/"
2994 if (entryName.length() < minEntryLen ||
2995 !entryName.endsWith(libSuffix) ||
2996 !entryName.startsWith(apkLib) ) {
2997 continue;
2998 }
2999
3000 // file name must start with libPrefix, i.e. "lib"
3001 int lastSlash = entryName.lastIndexOf('/');
3002
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003003 if (lastSlash < 0 ||
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08003004 !entryName.regionMatches(lastSlash+1, libPrefix, 0, libPrefixLen) ) {
3005 continue;
3006 }
3007
3008 hasNativeLibraries = true;
3009
3010 // check the cpuAbi now, between lib/ and /lib<name>.so
3011 //
3012 if (lastSlash != apkLibLen + cpuAbiLen ||
3013 !entryName.regionMatches(apkLibLen, cpuAbi, 0, cpuAbiLen) )
3014 continue;
3015
3016 // extract the library file name, ensure it doesn't contain
3017 // weird characters. we're guaranteed here that it doesn't contain
3018 // a directory separator though.
3019 String libFileName = entryName.substring(lastSlash+1);
3020 if (!FileUtils.isFilenameSafe(new File(libFileName))) {
3021 continue;
3022 }
3023
3024 installedNativeLibraries = true;
3025
3026 String sharedLibraryFilePath = sharedLibraryDir.getPath() +
3027 File.separator + libFileName;
3028 File sharedLibraryFile = new File(sharedLibraryFilePath);
3029 if (! sharedLibraryFile.exists() ||
3030 sharedLibraryFile.length() != entry.getSize() ||
3031 sharedLibraryFile.lastModified() != entry.getTime()) {
3032 if (Config.LOGD) {
3033 Log.d(TAG, "Caching shared lib " + entry.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 }
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08003035 if (mInstaller == null) {
3036 sharedLibraryDir.mkdir();
Dianne Hackbornb1811182009-05-21 15:45:42 -07003037 }
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003038 cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08003039 sharedLibraryFile);
3040 }
3041 }
3042 if (!hasNativeLibraries)
3043 return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
3044
3045 if (!installedNativeLibraries)
3046 return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH;
3047
3048 return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
3049 }
3050
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003051 // Find the gdbserver executable program in a package at
3052 // lib/<cpuAbi>/gdbserver and copy it to /data/data/<name>/lib/gdbserver
3053 //
3054 // Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success,
3055 // or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise.
3056 //
3057 private int cachePackageGdbServerLI(PackageParser.Package pkg,
3058 File dataPath, File scanFile, String cpuAbi) throws IOException, ZipException {
3059 File installGdbServerDir = new File(dataPath.getPath() + "/lib");
3060 final String GDBSERVER = "gdbserver";
3061 final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER;
3062
3063 ZipFile zipFile = new ZipFile(scanFile);
3064 Enumeration<ZipEntry> entries =
3065 (Enumeration<ZipEntry>) zipFile.entries();
3066
3067 while (entries.hasMoreElements()) {
3068 ZipEntry entry = entries.nextElement();
3069 // skip directories
3070 if (entry.isDirectory()) {
3071 continue;
3072 }
3073 String entryName = entry.getName();
3074
3075 if (!entryName.equals(apkGdbServerPath)) {
3076 continue;
3077 }
3078
3079 String installGdbServerPath = installGdbServerDir.getPath() +
3080 "/" + GDBSERVER;
3081 File installGdbServerFile = new File(installGdbServerPath);
3082 if (! installGdbServerFile.exists() ||
3083 installGdbServerFile.length() != entry.getSize() ||
3084 installGdbServerFile.lastModified() != entry.getTime()) {
3085 if (Config.LOGD) {
3086 Log.d(TAG, "Caching gdbserver " + entry.getName());
3087 }
3088 if (mInstaller == null) {
3089 installGdbServerDir.mkdir();
3090 }
3091 cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir,
3092 installGdbServerFile);
3093 }
3094 return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
3095 }
3096 return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
3097 }
3098
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08003099 // extract shared libraries stored in the APK as lib/<cpuAbi>/lib<name>.so
3100 // and copy them to /data/data/<appname>/lib.
3101 //
3102 // This function will first try the main CPU ABI defined by Build.CPU_ABI
3103 // (which corresponds to ro.product.cpu.abi), and also try an alternate
3104 // one if ro.product.cpu.abi2 is defined.
3105 //
3106 private int cachePackageSharedLibsLI(PackageParser.Package pkg,
3107 File dataPath, File scanFile) {
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003108 String cpuAbi = Build.CPU_ABI;
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08003109 try {
3110 int result = cachePackageSharedLibsForAbiLI(pkg, dataPath, scanFile, cpuAbi);
3111
3112 // some architectures are capable of supporting several CPU ABIs
3113 // for example, 'armeabi-v7a' also supports 'armeabi' native code
3114 // this is indicated by the definition of the ro.product.cpu.abi2
3115 // system property.
3116 //
3117 // only scan the package twice in case of ABI mismatch
3118 if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003119 final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null);
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08003120 if (cpuAbi2 != null) {
3121 result = cachePackageSharedLibsForAbiLI(pkg, dataPath, scanFile, cpuAbi2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003122 }
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08003123
3124 if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
3125 Log.w(TAG,"Native ABI mismatch from package file");
3126 return PackageManager.INSTALL_FAILED_INVALID_APK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003127 }
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003128
3129 if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
3130 cpuAbi = cpuAbi2;
3131 }
3132 }
3133
3134 // for debuggable packages, also extract gdbserver from lib/<abi>
3135 // into /data/data/<appname>/lib too.
3136 if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES &&
3137 (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
3138 int result2 = cachePackageGdbServerLI(pkg, dataPath, scanFile, cpuAbi);
3139 if (result2 == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
3140 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_NATIVE_DEBUGGABLE;
3141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003142 }
David 'Digit' Turnerfeba7432009-11-06 17:54:12 -08003143 } catch (ZipException e) {
3144 Log.w(TAG, "Failed to extract data from package file", e);
3145 return PackageManager.INSTALL_FAILED_INVALID_APK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146 } catch (IOException e) {
Dianne Hackbornb1811182009-05-21 15:45:42 -07003147 Log.w(TAG, "Failed to cache package shared libs", e);
3148 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003149 }
Dianne Hackbornb1811182009-05-21 15:45:42 -07003150 return PackageManager.INSTALL_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003151 }
3152
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003153 private void cacheNativeBinaryLI(PackageParser.Package pkg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003154 ZipFile zipFile, ZipEntry entry,
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003155 File binaryDir,
3156 File binaryFile) throws IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 InputStream inputStream = zipFile.getInputStream(entry);
3158 try {
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003159 File tempFile = File.createTempFile("tmp", "tmp", binaryDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 String tempFilePath = tempFile.getPath();
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003161 // XXX package manager can't change owner, so the executable files for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162 // now need to be left as world readable and owned by the system.
3163 if (! FileUtils.copyToFile(inputStream, tempFile) ||
3164 ! tempFile.setLastModified(entry.getTime()) ||
3165 FileUtils.setPermissions(tempFilePath,
3166 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003167 |FileUtils.S_IXUSR|FileUtils.S_IXGRP|FileUtils.S_IXOTH
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168 |FileUtils.S_IROTH, -1, -1) != 0 ||
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003169 ! tempFile.renameTo(binaryFile)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170 // Failed to properly write file.
3171 tempFile.delete();
David 'Digit' Turner1edab2b2010-01-21 15:15:23 -08003172 throw new IOException("Couldn't create cached binary "
3173 + binaryFile + " in " + binaryDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003174 }
3175 } finally {
3176 inputStream.close();
3177 }
3178 }
3179
3180 void removePackageLI(PackageParser.Package pkg, boolean chatty) {
3181 if (chatty && Config.LOGD) Log.d(
3182 TAG, "Removing package " + pkg.applicationInfo.packageName );
3183
3184 synchronized (mPackages) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003185 clearPackagePreferredActivitiesLP(pkg.packageName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 mPackages.remove(pkg.applicationInfo.packageName);
3188 if (pkg.mPath != null) {
3189 mAppDirs.remove(pkg.mPath);
3190 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003192 PackageSetting ps = (PackageSetting)pkg.mExtras;
3193 if (ps != null && ps.sharedUser != null) {
3194 // XXX don't do this until the data is removed.
3195 if (false) {
3196 ps.sharedUser.packages.remove(ps);
3197 if (ps.sharedUser.packages.size() == 0) {
3198 // Remove.
3199 }
3200 }
3201 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 int N = pkg.providers.size();
3204 StringBuilder r = null;
3205 int i;
3206 for (i=0; i<N; i++) {
3207 PackageParser.Provider p = pkg.providers.get(i);
3208 mProvidersByComponent.remove(new ComponentName(p.info.packageName,
3209 p.info.name));
3210 if (p.info.authority == null) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 /* The is another ContentProvider with this authority when
3213 * this app was installed so this authority is null,
3214 * Ignore it as we don't have to unregister the provider.
3215 */
3216 continue;
3217 }
3218 String names[] = p.info.authority.split(";");
3219 for (int j = 0; j < names.length; j++) {
3220 if (mProviders.get(names[j]) == p) {
3221 mProviders.remove(names[j]);
3222 if (chatty && Config.LOGD) Log.d(
3223 TAG, "Unregistered content provider: " + names[j] +
3224 ", className = " + p.info.name +
3225 ", isSyncable = " + p.info.isSyncable);
3226 }
3227 }
3228 if (chatty) {
3229 if (r == null) {
3230 r = new StringBuilder(256);
3231 } else {
3232 r.append(' ');
3233 }
3234 r.append(p.info.name);
3235 }
3236 }
3237 if (r != null) {
3238 if (Config.LOGD) Log.d(TAG, " Providers: " + r);
3239 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 N = pkg.services.size();
3242 r = null;
3243 for (i=0; i<N; i++) {
3244 PackageParser.Service s = pkg.services.get(i);
3245 mServices.removeService(s);
3246 if (chatty) {
3247 if (r == null) {
3248 r = new StringBuilder(256);
3249 } else {
3250 r.append(' ');
3251 }
3252 r.append(s.info.name);
3253 }
3254 }
3255 if (r != null) {
3256 if (Config.LOGD) Log.d(TAG, " Services: " + r);
3257 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003259 N = pkg.receivers.size();
3260 r = null;
3261 for (i=0; i<N; i++) {
3262 PackageParser.Activity a = pkg.receivers.get(i);
3263 mReceivers.removeActivity(a, "receiver");
3264 if (chatty) {
3265 if (r == null) {
3266 r = new StringBuilder(256);
3267 } else {
3268 r.append(' ');
3269 }
3270 r.append(a.info.name);
3271 }
3272 }
3273 if (r != null) {
3274 if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
3275 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 N = pkg.activities.size();
3278 r = null;
3279 for (i=0; i<N; i++) {
3280 PackageParser.Activity a = pkg.activities.get(i);
3281 mActivities.removeActivity(a, "activity");
3282 if (chatty) {
3283 if (r == null) {
3284 r = new StringBuilder(256);
3285 } else {
3286 r.append(' ');
3287 }
3288 r.append(a.info.name);
3289 }
3290 }
3291 if (r != null) {
3292 if (Config.LOGD) Log.d(TAG, " Activities: " + r);
3293 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 N = pkg.permissions.size();
3296 r = null;
3297 for (i=0; i<N; i++) {
3298 PackageParser.Permission p = pkg.permissions.get(i);
3299 boolean tree = false;
3300 BasePermission bp = mSettings.mPermissions.get(p.info.name);
3301 if (bp == null) {
3302 tree = true;
3303 bp = mSettings.mPermissionTrees.get(p.info.name);
3304 }
3305 if (bp != null && bp.perm == p) {
3306 if (bp.type != BasePermission.TYPE_BUILTIN) {
3307 if (tree) {
3308 mSettings.mPermissionTrees.remove(p.info.name);
3309 } else {
3310 mSettings.mPermissions.remove(p.info.name);
3311 }
3312 } else {
3313 bp.perm = null;
3314 }
3315 if (chatty) {
3316 if (r == null) {
3317 r = new StringBuilder(256);
3318 } else {
3319 r.append(' ');
3320 }
3321 r.append(p.info.name);
3322 }
3323 }
3324 }
3325 if (r != null) {
3326 if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
3327 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 N = pkg.instrumentation.size();
3330 r = null;
3331 for (i=0; i<N; i++) {
3332 PackageParser.Instrumentation a = pkg.instrumentation.get(i);
3333 mInstrumentation.remove(a.component);
3334 if (chatty) {
3335 if (r == null) {
3336 r = new StringBuilder(256);
3337 } else {
3338 r.append(' ');
3339 }
3340 r.append(a.info.name);
3341 }
3342 }
3343 if (r != null) {
3344 if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
3345 }
3346 }
3347 }
3348
3349 private static final boolean isPackageFilename(String name) {
3350 return name != null && name.endsWith(".apk");
3351 }
3352
3353 private void updatePermissionsLP() {
3354 // Make sure there are no dangling permission trees.
3355 Iterator<BasePermission> it = mSettings.mPermissionTrees
3356 .values().iterator();
3357 while (it.hasNext()) {
3358 BasePermission bp = it.next();
3359 if (bp.perm == null) {
3360 Log.w(TAG, "Removing dangling permission tree: " + bp.name
3361 + " from package " + bp.sourcePackage);
3362 it.remove();
3363 }
3364 }
3365
3366 // Make sure all dynamic permissions have been assigned to a package,
3367 // and make sure there are no dangling permissions.
3368 it = mSettings.mPermissions.values().iterator();
3369 while (it.hasNext()) {
3370 BasePermission bp = it.next();
3371 if (bp.type == BasePermission.TYPE_DYNAMIC) {
3372 if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
3373 + bp.name + " pkg=" + bp.sourcePackage
3374 + " info=" + bp.pendingInfo);
3375 if (bp.perm == null && bp.pendingInfo != null) {
3376 BasePermission tree = findPermissionTreeLP(bp.name);
3377 if (tree != null) {
3378 bp.perm = new PackageParser.Permission(tree.perm.owner,
3379 new PermissionInfo(bp.pendingInfo));
3380 bp.perm.info.packageName = tree.perm.info.packageName;
3381 bp.perm.info.name = bp.name;
3382 bp.uid = tree.uid;
3383 }
3384 }
3385 }
3386 if (bp.perm == null) {
3387 Log.w(TAG, "Removing dangling permission: " + bp.name
3388 + " from package " + bp.sourcePackage);
3389 it.remove();
3390 }
3391 }
3392
3393 // Now update the permissions for all packages, in particular
3394 // replace the granted permissions of the system packages.
3395 for (PackageParser.Package pkg : mPackages.values()) {
3396 grantPermissionsLP(pkg, false);
3397 }
3398 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003400 private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) {
3401 final PackageSetting ps = (PackageSetting)pkg.mExtras;
3402 if (ps == null) {
3403 return;
3404 }
3405 final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
3406 boolean addedPermission = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408 if (replace) {
3409 ps.permissionsFixed = false;
3410 if (gp == ps) {
3411 gp.grantedPermissions.clear();
3412 gp.gids = mGlobalGids;
3413 }
3414 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003416 if (gp.gids == null) {
3417 gp.gids = mGlobalGids;
3418 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003420 final int N = pkg.requestedPermissions.size();
3421 for (int i=0; i<N; i++) {
3422 String name = pkg.requestedPermissions.get(i);
3423 BasePermission bp = mSettings.mPermissions.get(name);
3424 PackageParser.Permission p = bp != null ? bp.perm : null;
3425 if (false) {
3426 if (gp != ps) {
3427 Log.i(TAG, "Package " + pkg.packageName + " checking " + name
3428 + ": " + p);
3429 }
3430 }
3431 if (p != null) {
3432 final String perm = p.info.name;
3433 boolean allowed;
3434 if (p.info.protectionLevel == PermissionInfo.PROTECTION_NORMAL
3435 || p.info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
3436 allowed = true;
3437 } else if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
3438 || p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07003439 allowed = (checkSignaturesLP(p.owner.mSignatures, pkg.mSignatures)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 == PackageManager.SIGNATURE_MATCH)
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07003441 || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442 == PackageManager.SIGNATURE_MATCH);
3443 if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
3444 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
3445 // For updated system applications, the signatureOrSystem permission
3446 // is granted only if it had been defined by the original application.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003447 if ((pkg.applicationInfo.flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
3449 PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName);
3450 if(sysPs.grantedPermissions.contains(perm)) {
3451 allowed = true;
3452 } else {
3453 allowed = false;
3454 }
3455 } else {
3456 allowed = true;
3457 }
3458 }
3459 }
3460 } else {
3461 allowed = false;
3462 }
3463 if (false) {
3464 if (gp != ps) {
3465 Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
3466 }
3467 }
3468 if (allowed) {
3469 if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0
3470 && ps.permissionsFixed) {
3471 // If this is an existing, non-system package, then
3472 // we can't add any new permissions to it.
3473 if (!gp.loadedPermissions.contains(perm)) {
3474 allowed = false;
Dianne Hackborn62da8462009-05-13 15:06:13 -07003475 // Except... if this is a permission that was added
3476 // to the platform (note: need to only do this when
3477 // updating the platform).
3478 final int NP = PackageParser.NEW_PERMISSIONS.length;
3479 for (int ip=0; ip<NP; ip++) {
3480 final PackageParser.NewPermissionInfo npi
3481 = PackageParser.NEW_PERMISSIONS[ip];
3482 if (npi.name.equals(perm)
3483 && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
3484 allowed = true;
San Mehat5a3a77d2009-06-01 09:25:28 -07003485 Log.i(TAG, "Auto-granting WRITE_EXTERNAL_STORAGE to old pkg "
Dianne Hackborn62da8462009-05-13 15:06:13 -07003486 + pkg.packageName);
3487 break;
3488 }
3489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 }
3491 }
3492 if (allowed) {
3493 if (!gp.grantedPermissions.contains(perm)) {
3494 addedPermission = true;
3495 gp.grantedPermissions.add(perm);
3496 gp.gids = appendInts(gp.gids, bp.gids);
3497 }
3498 } else {
3499 Log.w(TAG, "Not granting permission " + perm
3500 + " to package " + pkg.packageName
3501 + " because it was previously installed without");
3502 }
3503 } else {
3504 Log.w(TAG, "Not granting permission " + perm
3505 + " to package " + pkg.packageName
3506 + " (protectionLevel=" + p.info.protectionLevel
3507 + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
3508 + ")");
3509 }
3510 } else {
3511 Log.w(TAG, "Unknown permission " + name
3512 + " in package " + pkg.packageName);
3513 }
3514 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 if ((addedPermission || replace) && !ps.permissionsFixed &&
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07003517 ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) ||
3518 ((ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 // This is the first that we have heard about this package, so the
3520 // permissions we have now selected are fixed until explicitly
3521 // changed.
3522 ps.permissionsFixed = true;
3523 gp.loadedPermissions = new HashSet<String>(gp.grantedPermissions);
3524 }
3525 }
3526
3527 private final class ActivityIntentResolver
3528 extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
Mihai Preda074edef2009-05-18 17:13:31 +02003529 public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003530 mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
Mihai Preda074edef2009-05-18 17:13:31 +02003531 return super.queryIntent(intent, resolvedType, defaultOnly);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 }
3533
Mihai Preda074edef2009-05-18 17:13:31 +02003534 public List queryIntent(Intent intent, String resolvedType, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 mFlags = flags;
Mihai Preda074edef2009-05-18 17:13:31 +02003536 return super.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003537 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
3538 }
3539
Mihai Predaeae850c2009-05-13 10:13:48 +02003540 public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
3541 ArrayList<PackageParser.Activity> packageActivities) {
3542 if (packageActivities == null) {
3543 return null;
3544 }
3545 mFlags = flags;
3546 final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
3547 int N = packageActivities.size();
3548 ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut =
3549 new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N);
Mihai Predac3320db2009-05-18 20:15:32 +02003550
3551 ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
Mihai Predaeae850c2009-05-13 10:13:48 +02003552 for (int i = 0; i < N; ++i) {
Mihai Predac3320db2009-05-18 20:15:32 +02003553 intentFilters = packageActivities.get(i).intents;
3554 if (intentFilters != null && intentFilters.size() > 0) {
3555 listCut.add(intentFilters);
3556 }
Mihai Predaeae850c2009-05-13 10:13:48 +02003557 }
3558 return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
3559 }
3560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003561 public final void addActivity(PackageParser.Activity a, String type) {
3562 mActivities.put(a.component, a);
3563 if (SHOW_INFO || Config.LOGV) Log.v(
3564 TAG, " " + type + " " +
3565 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
3566 if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
3567 int NI = a.intents.size();
Mihai Predaeae850c2009-05-13 10:13:48 +02003568 for (int j=0; j<NI; j++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
3570 if (SHOW_INFO || Config.LOGV) {
3571 Log.v(TAG, " IntentFilter:");
3572 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3573 }
3574 if (!intent.debugCheck()) {
3575 Log.w(TAG, "==> For Activity " + a.info.name);
3576 }
3577 addFilter(intent);
3578 }
3579 }
3580
3581 public final void removeActivity(PackageParser.Activity a, String type) {
3582 mActivities.remove(a.component);
3583 if (SHOW_INFO || Config.LOGV) Log.v(
3584 TAG, " " + type + " " +
3585 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
3586 if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
3587 int NI = a.intents.size();
Mihai Predaeae850c2009-05-13 10:13:48 +02003588 for (int j=0; j<NI; j++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003589 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
3590 if (SHOW_INFO || Config.LOGV) {
3591 Log.v(TAG, " IntentFilter:");
3592 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3593 }
3594 removeFilter(intent);
3595 }
3596 }
3597
3598 @Override
3599 protected boolean allowFilterResult(
3600 PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {
3601 ActivityInfo filterAi = filter.activity.info;
3602 for (int i=dest.size()-1; i>=0; i--) {
3603 ActivityInfo destAi = dest.get(i).activityInfo;
3604 if (destAi.name == filterAi.name
3605 && destAi.packageName == filterAi.packageName) {
3606 return false;
3607 }
3608 }
3609 return true;
3610 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003612 @Override
3613 protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
3614 int match) {
3615 if (!mSettings.isEnabledLP(info.activity.info, mFlags)) {
3616 return null;
3617 }
3618 final PackageParser.Activity activity = info.activity;
3619 if (mSafeMode && (activity.info.applicationInfo.flags
3620 &ApplicationInfo.FLAG_SYSTEM) == 0) {
3621 return null;
3622 }
3623 final ResolveInfo res = new ResolveInfo();
3624 res.activityInfo = PackageParser.generateActivityInfo(activity,
3625 mFlags);
3626 if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
3627 res.filter = info;
3628 }
3629 res.priority = info.getPriority();
3630 res.preferredOrder = activity.owner.mPreferredOrder;
3631 //System.out.println("Result: " + res.activityInfo.className +
3632 // " = " + res.priority);
3633 res.match = match;
3634 res.isDefault = info.hasDefault;
3635 res.labelRes = info.labelRes;
3636 res.nonLocalizedLabel = info.nonLocalizedLabel;
3637 res.icon = info.icon;
3638 return res;
3639 }
3640
3641 @Override
3642 protected void sortResults(List<ResolveInfo> results) {
3643 Collections.sort(results, mResolvePrioritySorter);
3644 }
3645
3646 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003647 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 PackageParser.ActivityIntentInfo filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003649 out.print(prefix); out.print(
3650 Integer.toHexString(System.identityHashCode(filter.activity)));
3651 out.print(' ');
3652 out.println(filter.activity.componentShortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 }
3654
3655// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
3656// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
3657// final List<ResolveInfo> retList = Lists.newArrayList();
3658// while (i.hasNext()) {
3659// final ResolveInfo resolveInfo = i.next();
3660// if (isEnabledLP(resolveInfo.activityInfo)) {
3661// retList.add(resolveInfo);
3662// }
3663// }
3664// return retList;
3665// }
3666
3667 // Keys are String (activity class name), values are Activity.
3668 private final HashMap<ComponentName, PackageParser.Activity> mActivities
3669 = new HashMap<ComponentName, PackageParser.Activity>();
3670 private int mFlags;
3671 }
3672
3673 private final class ServiceIntentResolver
3674 extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
Mihai Preda074edef2009-05-18 17:13:31 +02003675 public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003676 mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
Mihai Preda074edef2009-05-18 17:13:31 +02003677 return super.queryIntent(intent, resolvedType, defaultOnly);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003678 }
3679
Mihai Preda074edef2009-05-18 17:13:31 +02003680 public List queryIntent(Intent intent, String resolvedType, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003681 mFlags = flags;
Mihai Preda074edef2009-05-18 17:13:31 +02003682 return super.queryIntent(intent, resolvedType,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003683 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
3684 }
3685
Dianne Hackbornc14b9ccd2009-06-17 18:02:12 -07003686 public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
3687 ArrayList<PackageParser.Service> packageServices) {
3688 if (packageServices == null) {
3689 return null;
3690 }
3691 mFlags = flags;
3692 final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
3693 int N = packageServices.size();
3694 ArrayList<ArrayList<PackageParser.ServiceIntentInfo>> listCut =
3695 new ArrayList<ArrayList<PackageParser.ServiceIntentInfo>>(N);
3696
3697 ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
3698 for (int i = 0; i < N; ++i) {
3699 intentFilters = packageServices.get(i).intents;
3700 if (intentFilters != null && intentFilters.size() > 0) {
3701 listCut.add(intentFilters);
3702 }
3703 }
3704 return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
3705 }
3706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 public final void addService(PackageParser.Service s) {
3708 mServices.put(s.component, s);
3709 if (SHOW_INFO || Config.LOGV) Log.v(
3710 TAG, " " + (s.info.nonLocalizedLabel != null
3711 ? s.info.nonLocalizedLabel : s.info.name) + ":");
3712 if (SHOW_INFO || Config.LOGV) Log.v(
3713 TAG, " Class=" + s.info.name);
3714 int NI = s.intents.size();
3715 int j;
3716 for (j=0; j<NI; j++) {
3717 PackageParser.ServiceIntentInfo intent = s.intents.get(j);
3718 if (SHOW_INFO || Config.LOGV) {
3719 Log.v(TAG, " IntentFilter:");
3720 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3721 }
3722 if (!intent.debugCheck()) {
3723 Log.w(TAG, "==> For Service " + s.info.name);
3724 }
3725 addFilter(intent);
3726 }
3727 }
3728
3729 public final void removeService(PackageParser.Service s) {
3730 mServices.remove(s.component);
3731 if (SHOW_INFO || Config.LOGV) Log.v(
3732 TAG, " " + (s.info.nonLocalizedLabel != null
3733 ? s.info.nonLocalizedLabel : s.info.name) + ":");
3734 if (SHOW_INFO || Config.LOGV) Log.v(
3735 TAG, " Class=" + s.info.name);
3736 int NI = s.intents.size();
3737 int j;
3738 for (j=0; j<NI; j++) {
3739 PackageParser.ServiceIntentInfo intent = s.intents.get(j);
3740 if (SHOW_INFO || Config.LOGV) {
3741 Log.v(TAG, " IntentFilter:");
3742 intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
3743 }
3744 removeFilter(intent);
3745 }
3746 }
3747
3748 @Override
3749 protected boolean allowFilterResult(
3750 PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) {
3751 ServiceInfo filterSi = filter.service.info;
3752 for (int i=dest.size()-1; i>=0; i--) {
3753 ServiceInfo destAi = dest.get(i).serviceInfo;
3754 if (destAi.name == filterSi.name
3755 && destAi.packageName == filterSi.packageName) {
3756 return false;
3757 }
3758 }
3759 return true;
3760 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003762 @Override
3763 protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
3764 int match) {
3765 final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
3766 if (!mSettings.isEnabledLP(info.service.info, mFlags)) {
3767 return null;
3768 }
3769 final PackageParser.Service service = info.service;
3770 if (mSafeMode && (service.info.applicationInfo.flags
3771 &ApplicationInfo.FLAG_SYSTEM) == 0) {
3772 return null;
3773 }
3774 final ResolveInfo res = new ResolveInfo();
3775 res.serviceInfo = PackageParser.generateServiceInfo(service,
3776 mFlags);
3777 if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
3778 res.filter = filter;
3779 }
3780 res.priority = info.getPriority();
3781 res.preferredOrder = service.owner.mPreferredOrder;
3782 //System.out.println("Result: " + res.activityInfo.className +
3783 // " = " + res.priority);
3784 res.match = match;
3785 res.isDefault = info.hasDefault;
3786 res.labelRes = info.labelRes;
3787 res.nonLocalizedLabel = info.nonLocalizedLabel;
3788 res.icon = info.icon;
3789 return res;
3790 }
3791
3792 @Override
3793 protected void sortResults(List<ResolveInfo> results) {
3794 Collections.sort(results, mResolvePrioritySorter);
3795 }
3796
3797 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003798 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003799 PackageParser.ServiceIntentInfo filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003800 out.print(prefix); out.print(
3801 Integer.toHexString(System.identityHashCode(filter.service)));
3802 out.print(' ');
3803 out.println(filter.service.componentShortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 }
3805
3806// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
3807// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
3808// final List<ResolveInfo> retList = Lists.newArrayList();
3809// while (i.hasNext()) {
3810// final ResolveInfo resolveInfo = (ResolveInfo) i;
3811// if (isEnabledLP(resolveInfo.serviceInfo)) {
3812// retList.add(resolveInfo);
3813// }
3814// }
3815// return retList;
3816// }
3817
3818 // Keys are String (activity class name), values are Activity.
3819 private final HashMap<ComponentName, PackageParser.Service> mServices
3820 = new HashMap<ComponentName, PackageParser.Service>();
3821 private int mFlags;
3822 };
3823
3824 private static final Comparator<ResolveInfo> mResolvePrioritySorter =
3825 new Comparator<ResolveInfo>() {
3826 public int compare(ResolveInfo r1, ResolveInfo r2) {
3827 int v1 = r1.priority;
3828 int v2 = r2.priority;
3829 //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
3830 if (v1 != v2) {
3831 return (v1 > v2) ? -1 : 1;
3832 }
3833 v1 = r1.preferredOrder;
3834 v2 = r2.preferredOrder;
3835 if (v1 != v2) {
3836 return (v1 > v2) ? -1 : 1;
3837 }
3838 if (r1.isDefault != r2.isDefault) {
3839 return r1.isDefault ? -1 : 1;
3840 }
3841 v1 = r1.match;
3842 v2 = r2.match;
3843 //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
3844 return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
3845 }
3846 };
3847
3848 private static final Comparator<ProviderInfo> mProviderInitOrderSorter =
3849 new Comparator<ProviderInfo>() {
3850 public int compare(ProviderInfo p1, ProviderInfo p2) {
3851 final int v1 = p1.initOrder;
3852 final int v2 = p2.initOrder;
3853 return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
3854 }
3855 };
3856
3857 private static final void sendPackageBroadcast(String action, String pkg, Bundle extras) {
3858 IActivityManager am = ActivityManagerNative.getDefault();
3859 if (am != null) {
3860 try {
3861 final Intent intent = new Intent(action,
3862 pkg != null ? Uri.fromParts("package", pkg, null) : null);
3863 if (extras != null) {
3864 intent.putExtras(extras);
3865 }
Dianne Hackbornde7faf62009-06-30 13:27:30 -07003866 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003867 am.broadcastIntent(
3868 null, intent,
3869 null, null, 0, null, null, null, false, false);
3870 } catch (RemoteException ex) {
3871 }
3872 }
3873 }
3874
3875 private final class AppDirObserver extends FileObserver {
3876 public AppDirObserver(String path, int mask, boolean isrom) {
3877 super(path, mask);
3878 mRootDir = path;
3879 mIsRom = isrom;
3880 }
3881
3882 public void onEvent(int event, String path) {
3883 String removedPackage = null;
3884 int removedUid = -1;
3885 String addedPackage = null;
3886 int addedUid = -1;
3887
3888 synchronized (mInstallLock) {
3889 String fullPathStr = null;
3890 File fullPath = null;
3891 if (path != null) {
3892 fullPath = new File(mRootDir, path);
3893 fullPathStr = fullPath.getPath();
3894 }
3895
3896 if (Config.LOGV) Log.v(
3897 TAG, "File " + fullPathStr + " changed: "
3898 + Integer.toHexString(event));
3899
3900 if (!isPackageFilename(path)) {
3901 if (Config.LOGV) Log.v(
3902 TAG, "Ignoring change of non-package file: " + fullPathStr);
3903 return;
3904 }
3905
3906 if ((event&REMOVE_EVENTS) != 0) {
3907 synchronized (mInstallLock) {
3908 PackageParser.Package p = mAppDirs.get(fullPathStr);
3909 if (p != null) {
3910 removePackageLI(p, true);
3911 removedPackage = p.applicationInfo.packageName;
3912 removedUid = p.applicationInfo.uid;
3913 }
3914 }
3915 }
3916
3917 if ((event&ADD_EVENTS) != 0) {
3918 PackageParser.Package p = mAppDirs.get(fullPathStr);
3919 if (p == null) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08003920 p = scanPackageLI(fullPath,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003921 (mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) |
3922 PackageParser.PARSE_CHATTY |
3923 PackageParser.PARSE_MUST_BE_APK,
Andrew Stadler48c02732010-01-15 00:03:41 -08003924 SCAN_MONITOR | SCAN_NO_PATHS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003925 if (p != null) {
3926 synchronized (mPackages) {
3927 grantPermissionsLP(p, false);
3928 }
3929 addedPackage = p.applicationInfo.packageName;
3930 addedUid = p.applicationInfo.uid;
3931 }
3932 }
3933 }
3934
3935 synchronized (mPackages) {
3936 mSettings.writeLP();
3937 }
3938 }
3939
3940 if (removedPackage != null) {
3941 Bundle extras = new Bundle(1);
3942 extras.putInt(Intent.EXTRA_UID, removedUid);
3943 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
3944 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
3945 }
3946 if (addedPackage != null) {
3947 Bundle extras = new Bundle(1);
3948 extras.putInt(Intent.EXTRA_UID, addedUid);
3949 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras);
3950 }
3951 }
3952
3953 private final String mRootDir;
3954 private final boolean mIsRom;
3955 }
Jacek Surazski65e13172009-04-28 15:26:38 +02003956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003957 /* Called when a downloaded package installation has been confirmed by the user */
3958 public void installPackage(
3959 final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
Jacek Surazski65e13172009-04-28 15:26:38 +02003960 installPackage(packageURI, observer, flags, null);
3961 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003962
Jacek Surazski65e13172009-04-28 15:26:38 +02003963 /* Called when a downloaded package installation has been confirmed by the user */
3964 public void installPackage(
3965 final Uri packageURI, final IPackageInstallObserver observer, final int flags,
3966 final String installerPackageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003967 mContext.enforceCallingOrSelfPermission(
3968 android.Manifest.permission.INSTALL_PACKAGES, null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003969
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08003970 Message msg = mHandler.obtainMessage(INIT_COPY);
3971 msg.obj = createInstallArgs(packageURI, observer, flags, installerPackageName);
3972 mHandler.sendMessage(msg);
3973 }
3974
3975 private InstallArgs createInstallArgs(Uri packageURI, IPackageInstallObserver observer,
3976 int flags, String installerPackageName) {
3977 if (installOnSd(flags)) {
3978 return new SdInstallArgs(packageURI, observer, flags,
3979 installerPackageName);
3980 } else {
3981 return new FileInstallArgs(packageURI, observer, flags,
3982 installerPackageName);
3983 }
3984 }
3985
3986 private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) {
3987 if (installOnSd(flags)) {
3988 return new SdInstallArgs(fullCodePath, fullResourcePath);
3989 } else {
3990 return new FileInstallArgs(fullCodePath, fullResourcePath);
3991 }
3992 }
3993
3994 private void processPendingInstall(final InstallArgs args, final int currentStatus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003995 // Queue up an async operation since the package installation may take a little while.
3996 mHandler.post(new Runnable() {
3997 public void run() {
3998 mHandler.removeCallbacks(this);
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07003999 // Result object to be returned
4000 PackageInstalledInfo res = new PackageInstalledInfo();
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004001 res.returnCode = currentStatus;
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07004002 res.uid = -1;
4003 res.pkg = null;
4004 res.removedInfo = new PackageRemovedInfo();
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004005 args.doPreInstall(res.returnCode);
4006 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07004007 synchronized (mInstallLock) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004008 installPackageLI(args, true, res);
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07004009 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004010 args.doPostInstall(res.returnCode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004012 if (args.observer != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004013 try {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004014 args.observer.packageInstalled(res.name, res.returnCode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004015 } catch (RemoteException e) {
4016 Log.i(TAG, "Observer no longer exists.");
4017 }
4018 }
4019 // There appears to be a subtle deadlock condition if the sendPackageBroadcast
4020 // call appears in the synchronized block above.
4021 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
4022 res.removedInfo.sendBroadcast(false, true);
4023 Bundle extras = new Bundle(1);
4024 extras.putInt(Intent.EXTRA_UID, res.uid);
Dianne Hackbornf63220f2009-03-24 18:38:43 -07004025 final boolean update = res.removedInfo.removedPackage != null;
4026 if (update) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027 extras.putBoolean(Intent.EXTRA_REPLACING, true);
4028 }
4029 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
4030 res.pkg.applicationInfo.packageName,
4031 extras);
Dianne Hackbornf63220f2009-03-24 18:38:43 -07004032 if (update) {
4033 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
4034 res.pkg.applicationInfo.packageName,
4035 extras);
4036 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004037 if (res.removedInfo.args != null) {
4038 // Remove the replaced package's older resources safely now
4039 synchronized (mInstallLock) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004040 res.removedInfo.args.doPostDeleteLI(true);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004041 }
4042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 }
4044 Runtime.getRuntime().gc();
4045 }
4046 });
4047 }
4048
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004049 static abstract class InstallArgs {
4050 final IPackageInstallObserver observer;
4051 final int flags;
4052 final Uri packageURI;
4053 final String installerPackageName;
4054
4055 InstallArgs(Uri packageURI,
4056 IPackageInstallObserver observer, int flags,
4057 String installerPackageName) {
4058 this.packageURI = packageURI;
4059 this.flags = flags;
4060 this.observer = observer;
4061 this.installerPackageName = installerPackageName;
4062 }
4063
4064 abstract void createCopyFile();
4065 abstract int copyApk(IMediaContainerService imcs);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004066 abstract int doPreInstall(int status);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004067 abstract boolean doRename(int status, String pkgName, String oldCodePath);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004068 abstract int doPostInstall(int status);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004069 abstract String getCodePath();
4070 abstract String getResourcePath();
4071 // Need installer lock especially for dex file removal.
4072 abstract void cleanUpResourcesLI();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004073 abstract boolean doPostDeleteLI(boolean delete);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004074 }
4075
4076 class FileInstallArgs extends InstallArgs {
4077 File installDir;
4078 String codeFileName;
4079 String resourceFileName;
4080
4081 FileInstallArgs(Uri packageURI,
4082 IPackageInstallObserver observer, int flags,
4083 String installerPackageName) {
4084 super(packageURI, observer, flags, installerPackageName);
4085 }
4086
4087 FileInstallArgs(String fullCodePath, String fullResourcePath) {
4088 super(null, null, 0, null);
4089 File codeFile = new File(fullCodePath);
4090 installDir = codeFile.getParentFile();
4091 codeFileName = fullCodePath;
4092 resourceFileName = fullResourcePath;
4093 }
4094
4095 void createCopyFile() {
4096 boolean fwdLocked = isFwdLocked(flags);
4097 installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
4098 codeFileName = createTempPackageFile(installDir).getPath();
4099 resourceFileName = getResourcePathFromCodePath();
4100 }
4101
4102 String getCodePath() {
4103 return codeFileName;
4104 }
4105
4106 int copyApk(IMediaContainerService imcs) {
4107 // Get a ParcelFileDescriptor to write to the output file
4108 File codeFile = new File(codeFileName);
4109 ParcelFileDescriptor out = null;
4110 try {
4111 out = ParcelFileDescriptor.open(codeFile,
4112 ParcelFileDescriptor.MODE_READ_WRITE);
4113 } catch (FileNotFoundException e) {
4114 Log.e(TAG, "Failed to create file descritpor for : " + codeFileName);
4115 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
4116 }
4117 // Copy the resource now
4118 int ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
4119 try {
4120 if (imcs.copyResource(packageURI, out)) {
4121 ret = PackageManager.INSTALL_SUCCEEDED;
4122 }
4123 } catch (RemoteException e) {
4124 } finally {
4125 try { if (out != null) out.close(); } catch (IOException e) {}
4126 }
4127 return ret;
4128 }
4129
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004130 int doPreInstall(int status) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004131 if (status != PackageManager.INSTALL_SUCCEEDED) {
4132 cleanUp();
4133 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004134 return status;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004135 }
4136
4137 boolean doRename(int status, final String pkgName, String oldCodePath) {
4138 if (status != PackageManager.INSTALL_SUCCEEDED) {
4139 cleanUp();
4140 return false;
4141 } else {
4142 // Rename based on packageName
4143 File codeFile = new File(getCodePath());
4144 String apkName = getNextCodePath(oldCodePath, pkgName, ".apk");
4145 File desFile = new File(installDir, apkName + ".apk");
4146 if (!codeFile.renameTo(desFile)) {
4147 return false;
4148 }
4149 // Reset paths since the file has been renamed.
4150 codeFileName = desFile.getPath();
4151 resourceFileName = getResourcePathFromCodePath();
4152 // Set permissions
4153 if (!setPermissions(pkgName)) {
4154 // Failed setting permissions.
4155 return false;
4156 }
4157 return true;
4158 }
4159 }
4160
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004161 int doPostInstall(int status) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004162 if (status != PackageManager.INSTALL_SUCCEEDED) {
4163 cleanUp();
4164 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004165 return status;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004166 }
4167
4168 String getResourcePath() {
4169 return resourceFileName;
4170 }
4171
4172 String getResourcePathFromCodePath() {
4173 String codePath = getCodePath();
4174 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
4175 String apkNameOnly = getApkName(codePath);
4176 return mAppInstallDir.getPath() + "/" + apkNameOnly + ".zip";
4177 } else {
4178 return codePath;
4179 }
4180 }
4181
4182 private boolean cleanUp() {
4183 boolean ret = true;
4184 String sourceDir = getCodePath();
4185 String publicSourceDir = getResourcePath();
4186 if (sourceDir != null) {
4187 File sourceFile = new File(sourceDir);
4188 if (!sourceFile.exists()) {
4189 Log.w(TAG, "Package source " + sourceDir + " does not exist.");
4190 ret = false;
4191 }
4192 // Delete application's code and resources
4193 sourceFile.delete();
4194 }
4195 if (publicSourceDir != null && !publicSourceDir.equals(sourceDir)) {
4196 final File publicSourceFile = new File(publicSourceDir);
4197 if (!publicSourceFile.exists()) {
4198 Log.w(TAG, "Package public source " + publicSourceFile + " does not exist.");
4199 }
4200 if (publicSourceFile.exists()) {
4201 publicSourceFile.delete();
4202 }
4203 }
4204 return ret;
4205 }
4206
4207 void cleanUpResourcesLI() {
4208 String sourceDir = getCodePath();
4209 if (cleanUp() && mInstaller != null) {
4210 int retCode = mInstaller.rmdex(sourceDir);
4211 if (retCode < 0) {
4212 Log.w(TAG, "Couldn't remove dex file for package: "
4213 + " at location "
4214 + sourceDir + ", retcode=" + retCode);
4215 // we don't consider this to be a failure of the core package deletion
4216 }
4217 }
4218 }
4219
4220 private boolean setPermissions(String pkgName) {
4221 // TODO Do this in a more elegant way later on. for now just a hack
4222 if (!isFwdLocked(flags)) {
4223 final int filePermissions =
4224 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
4225 |FileUtils.S_IROTH;
4226 int retCode = FileUtils.setPermissions(getCodePath(), filePermissions, -1, -1);
4227 if (retCode != 0) {
4228 Log.e(TAG, "Couldn't set new package file permissions for " +
4229 getCodePath()
4230 + ". The return code was: " + retCode);
4231 // TODO Define new internal error
4232 return false;
4233 }
4234 return true;
4235 }
4236 return true;
4237 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004238
4239 boolean doPostDeleteLI(boolean delete) {
4240 cleanUpResourcesLI();
4241 return true;
4242 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004243 }
4244
4245 class SdInstallArgs extends InstallArgs {
4246 String cid;
4247 String cachePath;
4248 static final String RES_FILE_NAME = "pkg.apk";
4249
4250 SdInstallArgs(Uri packageURI,
4251 IPackageInstallObserver observer, int flags,
4252 String installerPackageName) {
4253 super(packageURI, observer, flags, installerPackageName);
4254 }
4255
4256 SdInstallArgs(String fullCodePath, String fullResourcePath) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004257 super(null, null, ApplicationInfo.FLAG_ON_SDCARD, null);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004258 // Extract cid from fullCodePath
4259 int eidx = fullCodePath.lastIndexOf("/");
4260 String subStr1 = fullCodePath.substring(0, eidx);
4261 int sidx = subStr1.lastIndexOf("/");
4262 cid = subStr1.substring(sidx+1, eidx);
4263 cachePath = subStr1;
4264 }
4265
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004266 SdInstallArgs(String cid) {
4267 super(null, null, ApplicationInfo.FLAG_ON_SDCARD, null);
4268 this.cid = cid;
4269 }
4270
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004271 void createCopyFile() {
4272 cid = getTempContainerId();
4273 }
4274
4275 int copyApk(IMediaContainerService imcs) {
4276 try {
4277 cachePath = imcs.copyResourceToContainer(
4278 packageURI, cid,
4279 getEncryptKey(), RES_FILE_NAME);
4280 } catch (RemoteException e) {
4281 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004282 return (cachePath == null) ? PackageManager.INSTALL_FAILED_CONTAINER_ERROR :
4283 PackageManager.INSTALL_SUCCEEDED;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004284 }
4285
4286 @Override
4287 String getCodePath() {
4288 return cachePath + "/" + RES_FILE_NAME;
4289 }
4290
4291 @Override
4292 String getResourcePath() {
4293 return cachePath + "/" + RES_FILE_NAME;
4294 }
4295
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004296 int doPreInstall(int status) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004297 if (status != PackageManager.INSTALL_SUCCEEDED) {
4298 // Destroy container
4299 destroySdDir(cid);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004300 } else {
4301 // STOPSHIP Remove once new api is added in MountService
4302 //boolean mounted = isContainerMounted(cid);
4303 boolean mounted = false;
4304 if (!mounted) {
4305 cachePath = mountSdDir(cid, Process.SYSTEM_UID);
4306 if (cachePath == null) {
4307 return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
4308 }
4309 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004310 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004311 return status;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004312 }
4313
4314 boolean doRename(int status, final String pkgName,
4315 String oldCodePath) {
4316 String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004317 String newCachePath = null;
4318 /*final int RENAME_FAILED = 1;
4319 final int MOUNT_FAILED = 2;
4320 final int DESTROY_FAILED = 3;
4321 final int PASS = 4;
4322 int errCode = RENAME_FAILED;
4323 if (mounted) {
4324 // Unmount the container
4325 if (!unMountSdDir(cid)) {
4326 Log.i(TAG, "Failed to unmount " + cid + " before renaming");
4327 return false;
4328 }
4329 mounted = false;
4330 }
4331 if (renameSdDir(cid, newCacheId)) {
4332 errCode = MOUNT_FAILED;
4333 if ((newCachePath = mountSdDir(newCacheId, Process.SYSTEM_UID)) != null) {
4334 errCode = PASS;
4335 }
4336 }
4337 String errMsg = "";
4338 switch (errCode) {
4339 case RENAME_FAILED:
4340 errMsg = "RENAME_FAILED";
4341 break;
4342 case MOUNT_FAILED:
4343 errMsg = "MOUNT_FAILED";
4344 break;
4345 case DESTROY_FAILED:
4346 errMsg = "DESTROY_FAILED";
4347 break;
4348 default:
4349 errMsg = "PASS";
4350 break;
4351 }
4352 Log.i(TAG, "Status: " + errMsg);
4353 if (errCode != PASS) {
4354 return false;
4355 }
4356 Log.i(TAG, "Succesfully renamed " + cid + " to " +newCacheId +
4357 " at path: " + cachePath + " to new path: " + newCachePath);
4358 cid = newCacheId;
4359 cachePath = newCachePath;
4360 return true;
4361 */
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004362 // STOPSHIP TEMPORARY HACK FOR RENAME
4363 // Create new container at newCachePath
4364 String codePath = getCodePath();
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004365 final int CREATE_FAILED = 1;
4366 final int COPY_FAILED = 3;
4367 final int FINALIZE_FAILED = 5;
4368 final int PASS = 7;
4369 int errCode = CREATE_FAILED;
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004370
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004371 if ((newCachePath = createSdDir(new File(codePath), newCacheId)) != null) {
4372 errCode = COPY_FAILED;
4373 // Copy file from codePath
4374 if (FileUtils.copyFile(new File(codePath), new File(newCachePath, RES_FILE_NAME))) {
4375 errCode = FINALIZE_FAILED;
4376 if (finalizeSdDir(newCacheId)) {
4377 errCode = PASS;
4378 }
4379 }
4380 }
4381 // Print error based on errCode
4382 String errMsg = "";
4383 switch (errCode) {
4384 case CREATE_FAILED:
4385 errMsg = "CREATE_FAILED";
4386 break;
4387 case COPY_FAILED:
4388 errMsg = "COPY_FAILED";
4389 destroySdDir(newCacheId);
4390 break;
4391 case FINALIZE_FAILED:
4392 errMsg = "FINALIZE_FAILED";
4393 destroySdDir(newCacheId);
4394 break;
4395 default:
4396 errMsg = "PASS";
4397 break;
4398 }
4399 // Destroy the temporary container
4400 destroySdDir(cid);
4401 Log.i(TAG, "Status: " + errMsg);
4402 if (errCode != PASS) {
4403 return false;
4404 }
4405 cid = newCacheId;
4406 cachePath = newCachePath;
4407
4408 return true;
4409 }
4410
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004411 int doPostInstall(int status) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004412 if (status != PackageManager.INSTALL_SUCCEEDED) {
4413 cleanUp();
4414 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004415 // STOP SHIP Change this once new api is added.
4416 //boolean mounted = isContainerMounted(cid);
4417 boolean mounted = false;
4418 if (!mounted) {
4419 mountSdDir(cid, Process.SYSTEM_UID);
4420 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004421 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004422 return status;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004423 }
4424
4425 private void cleanUp() {
4426 // Destroy secure container
4427 destroySdDir(cid);
4428 }
4429
4430 void cleanUpResourcesLI() {
4431 String sourceFile = getCodePath();
4432 // Remove dex file
4433 if (mInstaller != null) {
4434 int retCode = mInstaller.rmdex(sourceFile.toString());
4435 if (retCode < 0) {
4436 Log.w(TAG, "Couldn't remove dex file for package: "
4437 + " at location "
4438 + sourceFile.toString() + ", retcode=" + retCode);
4439 // we don't consider this to be a failure of the core package deletion
4440 }
4441 }
4442 cleanUp();
4443 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004444
4445 boolean matchContainer(String app) {
4446 if (cid.startsWith(app)) {
4447 return true;
4448 }
4449 return false;
4450 }
4451
4452 String getPackageName() {
4453 int idx = cid.lastIndexOf("-");
4454 if (idx == -1) {
4455 return cid;
4456 }
4457 return cid.substring(0, idx);
4458 }
4459
4460 boolean doPostDeleteLI(boolean delete) {
4461 boolean ret = false;
4462 boolean mounted = isContainerMounted(cid);
4463 if (mounted) {
4464 // Unmount first
4465 ret = unMountSdDir(cid);
4466 }
4467 if (ret && delete) {
4468 cleanUpResourcesLI();
4469 }
4470 return ret;
4471 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004472 };
4473
4474 // Utility method used to create code paths based on package name and available index.
4475 private static String getNextCodePath(String oldCodePath, String prefix, String suffix) {
4476 String idxStr = "";
4477 int idx = 1;
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004478 // Fall back to default value of idx=1 if prefix is not
4479 // part of oldCodePath
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004480 if (oldCodePath != null) {
Bjorn Bringert5fd5bfe2010-01-29 12:11:30 +00004481 String subStr = oldCodePath;
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004482 // Drop the suffix right away
Bjorn Bringert5fd5bfe2010-01-29 12:11:30 +00004483 if (subStr.endsWith(suffix)) {
4484 subStr = subStr.substring(0, subStr.length() - suffix.length());
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004485 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004486 // If oldCodePath already contains prefix find out the
4487 // ending index to either increment or decrement.
4488 int sidx = subStr.lastIndexOf(prefix);
4489 if (sidx != -1) {
4490 subStr = subStr.substring(sidx + prefix.length());
4491 if (subStr != null) {
4492 if (subStr.startsWith("-")) {
4493 subStr = subStr.substring(1);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004494 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004495 try {
4496 idx = Integer.parseInt(subStr);
4497 if (idx <= 1) {
4498 idx++;
4499 } else {
4500 idx--;
4501 }
4502 } catch(NumberFormatException e) {
4503 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004504 }
4505 }
4506 }
4507 idxStr = "-" + Integer.toString(idx);
4508 return prefix + idxStr;
4509 }
4510
4511 // Utility method that returns the relative package path with respect
4512 // to the installation directory. Like say for /data/data/com.test-1.apk
4513 // string com.test-1 is returned.
4514 static String getApkName(String codePath) {
4515 if (codePath == null) {
4516 return null;
4517 }
4518 int sidx = codePath.lastIndexOf("/");
4519 int eidx = codePath.lastIndexOf(".");
4520 if (eidx == -1) {
4521 eidx = codePath.length();
4522 } else if (eidx == 0) {
4523 Log.w(TAG, " Invalid code path, "+ codePath + " Not a valid apk name");
4524 return null;
4525 }
4526 return codePath.substring(sidx+1, eidx);
4527 }
4528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004529 class PackageInstalledInfo {
4530 String name;
4531 int uid;
4532 PackageParser.Package pkg;
4533 int returnCode;
4534 PackageRemovedInfo removedInfo;
4535 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004537 /*
4538 * Install a non-existing package.
4539 */
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004540 private void installNewPackageLI(PackageParser.Package pkg,
4541 int parseFlags,
4542 int scanMode,
Jacek Surazski65e13172009-04-28 15:26:38 +02004543 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004544 // Remember this for later, in case we need to rollback this install
Oscar Montemayora8529f62009-11-18 10:14:20 -08004545 boolean dataDirExists;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004546 String pkgName = pkg.packageName;
Oscar Montemayora8529f62009-11-18 10:14:20 -08004547
4548 if (useEncryptedFilesystemForPackage(pkg)) {
4549 dataDirExists = (new File(mSecureAppDataDir, pkgName)).exists();
4550 } else {
4551 dataDirExists = (new File(mAppDataDir, pkgName)).exists();
4552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 res.name = pkgName;
4554 synchronized(mPackages) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004555 if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004556 // Don't allow installation over an existing package with the same name.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004557 Log.w(TAG, "Attempt to re-install " + pkgName
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004558 + " without first uninstalling.");
4559 res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
4560 return;
4561 }
4562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004563 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004564 PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004565 if (newPackage == null) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004566 Log.w(TAG, "Package couldn't be installed in " + pkg.mPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004567 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
4568 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
4569 }
4570 } else {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004571 updateSettingsLI(newPackage,
Jacek Surazski65e13172009-04-28 15:26:38 +02004572 installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004573 res);
4574 // delete the partially installed application. the data directory will have to be
4575 // restored if it was already existing
4576 if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
4577 // remove package from internal structures. Note that we want deletePackageX to
4578 // delete the package data and cache directories that it created in
4579 // scanPackageLocked, unless those directories existed before we even tried to
4580 // install.
4581 deletePackageLI(
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004582 pkgName, false,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004583 dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
4584 res.removedInfo);
4585 }
4586 }
4587 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004588
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004589 private void replacePackageLI(PackageParser.Package pkg,
4590 int parseFlags,
4591 int scanMode,
Jacek Surazski65e13172009-04-28 15:26:38 +02004592 String installerPackageName, PackageInstalledInfo res) {
4593
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004594 PackageParser.Package oldPackage;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004595 String pkgName = pkg.packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004596 // First find the old package info and check signatures
4597 synchronized(mPackages) {
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004598 oldPackage = mPackages.get(pkgName);
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07004599 if(checkSignaturesLP(pkg.mSignatures, oldPackage.mSignatures)
4600 != PackageManager.SIGNATURE_MATCH) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
4602 return;
4603 }
4604 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07004605 boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004606 if(sysPkg) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004607 replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 } else {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004609 replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004610 }
4611 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004613 private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004614 PackageParser.Package pkg,
4615 int parseFlags, int scanMode,
Jacek Surazski65e13172009-04-28 15:26:38 +02004616 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004617 PackageParser.Package newPackage = null;
4618 String pkgName = deletedPackage.packageName;
4619 boolean deletedPkg = true;
4620 boolean updatedSettings = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004621
Jacek Surazski65e13172009-04-28 15:26:38 +02004622 String oldInstallerPackageName = null;
4623 synchronized (mPackages) {
4624 oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
4625 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004626
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004627 parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004628 // First delete the existing package while retaining the data directory
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004629 if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004630 res.removedInfo)) {
4631 // If the existing package was'nt successfully deleted
4632 res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
4633 deletedPkg = false;
4634 } else {
4635 // Successfully deleted the old package. Now proceed with re-installation
4636 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004637 newPackage = scanPackageLI(pkg, parseFlags, scanMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004638 if (newPackage == null) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004639 Log.w(TAG, "Package couldn't be installed in " + pkg.mPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004640 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
4641 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
Suchi Amalapurapu110fea72010-01-14 17:50:23 -08004642 }
4643 } else {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004644 updateSettingsLI(newPackage,
Jacek Surazski65e13172009-04-28 15:26:38 +02004645 installerPackageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004646 res);
4647 updatedSettings = true;
4648 }
4649 }
4650
4651 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
4652 // If we deleted an exisiting package, the old source and resource files that we
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004653 // were keeping around in case we needed them (see below) can now be deleted.
4654 // This info will be set on the res.removedInfo to clean up later on as post
4655 // install action.
4656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004657 //update signature on the new package setting
4658 //this should always succeed, since we checked the
4659 //signature earlier.
4660 synchronized(mPackages) {
4661 verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg,
4662 parseFlags, true);
4663 }
4664 } else {
4665 // remove package from internal structures. Note that we want deletePackageX to
4666 // delete the package data and cache directories that it created in
4667 // scanPackageLocked, unless those directories existed before we even tried to
4668 // install.
4669 if(updatedSettings) {
4670 deletePackageLI(
4671 pkgName, true,
4672 PackageManager.DONT_DELETE_DATA,
4673 res.removedInfo);
4674 }
4675 // Since we failed to install the new package we need to restore the old
4676 // package that we deleted.
4677 if(deletedPkg) {
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07004678 File restoreFile = new File(deletedPackage.mPath);
4679 if (restoreFile == null) {
4680 Log.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
4681 return;
4682 }
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07004683 PackageInstalledInfo restoreRes = new PackageInstalledInfo();
4684 restoreRes.removedInfo = new PackageRemovedInfo();
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004685 // Parse old package
4686 parseFlags |= ~PackageManager.INSTALL_REPLACE_EXISTING;
4687 scanPackageLI(restoreFile, parseFlags, scanMode);
4688 synchronized (mPackages) {
4689 grantPermissionsLP(deletedPackage, false);
4690 mSettings.writeLP();
4691 }
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07004692 if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) {
4693 Log.e(TAG, "Failed restoring pkg : " + pkgName + " after failed upgrade");
4694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695 }
4696 }
4697 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004699 private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004700 PackageParser.Package pkg,
4701 int parseFlags, int scanMode,
Jacek Surazski65e13172009-04-28 15:26:38 +02004702 String installerPackageName, PackageInstalledInfo res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004703 PackageParser.Package newPackage = null;
4704 boolean updatedSettings = false;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004705 parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING |
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004706 PackageParser.PARSE_IS_SYSTEM;
4707 String packageName = deletedPackage.packageName;
4708 res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
4709 if (packageName == null) {
4710 Log.w(TAG, "Attempt to delete null packageName.");
4711 return;
4712 }
4713 PackageParser.Package oldPkg;
4714 PackageSetting oldPkgSetting;
4715 synchronized (mPackages) {
4716 oldPkg = mPackages.get(packageName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004717 oldPkgSetting = mSettings.mPackages.get(packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004718 if((oldPkg == null) || (oldPkg.applicationInfo == null) ||
4719 (oldPkgSetting == null)) {
4720 Log.w(TAG, "Could'nt find package:"+packageName+" information");
4721 return;
4722 }
4723 }
4724 res.removedInfo.uid = oldPkg.applicationInfo.uid;
4725 res.removedInfo.removedPackage = packageName;
4726 // Remove existing system package
4727 removePackageLI(oldPkg, true);
4728 synchronized (mPackages) {
4729 res.removedInfo.removedUid = mSettings.disableSystemPackageLP(packageName);
4730 }
4731
4732 // Successfully disabled the old package. Now proceed with re-installation
4733 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
4734 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004735 newPackage = scanPackageLI(pkg, parseFlags, scanMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004736 if (newPackage == null) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004737 Log.w(TAG, "Package couldn't be installed in " + pkg.mPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004738 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
4739 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
4740 }
4741 } else {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004742 updateSettingsLI(newPackage, installerPackageName, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004743 updatedSettings = true;
4744 }
4745
4746 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
4747 //update signature on the new package setting
4748 //this should always succeed, since we checked the
4749 //signature earlier.
4750 synchronized(mPackages) {
4751 verifySignaturesLP(mSettings.mPackages.get(packageName), pkg,
4752 parseFlags, true);
4753 }
4754 } else {
4755 // Re installation failed. Restore old information
4756 // Remove new pkg information
Dianne Hackborn62da8462009-05-13 15:06:13 -07004757 if (newPackage != null) {
4758 removePackageLI(newPackage, true);
4759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004760 // Add back the old system package
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004761 scanPackageLI(oldPkg, parseFlags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004762 SCAN_MONITOR
The Android Open Source Project10592532009-03-18 17:39:46 -07004763 | SCAN_UPDATE_SIGNATURE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004764 // Restore the old system information in Settings
4765 synchronized(mPackages) {
4766 if(updatedSettings) {
4767 mSettings.enableSystemPackageLP(packageName);
Jacek Surazski65e13172009-04-28 15:26:38 +02004768 mSettings.setInstallerPackageName(packageName,
4769 oldPkgSetting.installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004770 }
4771 mSettings.writeLP();
4772 }
4773 }
4774 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004775
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004776 private void updateSettingsLI(PackageParser.Package newPackage,
Jacek Surazski65e13172009-04-28 15:26:38 +02004777 String installerPackageName, PackageInstalledInfo res) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004778 String pkgName = newPackage.packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004779 synchronized (mPackages) {
4780 //write settings. the installStatus will be incomplete at this stage.
4781 //note that the new package setting would have already been
4782 //added to mPackages. It hasn't been persisted yet.
4783 mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE);
4784 mSettings.writeLP();
4785 }
4786
4787 int retCode = 0;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004788 if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
4789 retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004790 if (retCode != 0) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004791 Log.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004792 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
4793 return;
4794 }
4795 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004796 res.returnCode = setPermissionsLI(newPackage);
4797 if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
4798 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004799 } else {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004800 Log.d(TAG, "New package installed in " + newPackage.mPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004801 }
4802 if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
4803 if (mInstaller != null) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004804 mInstaller.rmdex(newPackage.mScanPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004805 }
4806 }
4807
4808 synchronized (mPackages) {
4809 grantPermissionsLP(newPackage, true);
4810 res.name = pkgName;
4811 res.uid = newPackage.applicationInfo.uid;
4812 res.pkg = newPackage;
4813 mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
Jacek Surazski65e13172009-04-28 15:26:38 +02004814 mSettings.setInstallerPackageName(pkgName, installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004815 res.returnCode = PackageManager.INSTALL_SUCCEEDED;
4816 //to update install status
4817 mSettings.writeLP();
4818 }
4819 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004820
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004821 private void installPackageLI(InstallArgs args,
4822 boolean newInstall, PackageInstalledInfo res) {
4823 int pFlags = args.flags;
4824 String installerPackageName = args.installerPackageName;
4825 File tmpPackageFile = new File(args.getCodePath());
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004826 boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
4827 boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0);
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07004828 boolean replacingExistingPackage = false;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004829 int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
4830 | (newInstall ? SCAN_NEW_INSTALL : 0);
Suchi Amalapurapuee5ece42009-09-15 13:41:47 -07004831 // Result object to be returned
4832 res.returnCode = PackageManager.INSTALL_SUCCEEDED;
4833
4834 main_flow: try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004835 // Retrieve PackageSettings and parse package
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004836 int parseFlags = PackageParser.PARSE_CHATTY |
4837 (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
4838 (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004839 parseFlags |= mDefParseFlags;
4840 PackageParser pp = new PackageParser(tmpPackageFile.getPath());
4841 pp.setSeparateProcesses(mSeparateProcesses);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004842 final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004843 null, mMetrics, parseFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004844 if (pkg == null) {
4845 res.returnCode = pp.getParseError();
4846 break main_flow;
4847 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004848 String pkgName = res.name = pkg.packageName;
Dianne Hackbornade3eca2009-05-11 18:54:45 -07004849 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
4850 if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
4851 res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
4852 break main_flow;
4853 }
4854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004855 if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
4856 res.returnCode = pp.getParseError();
4857 break main_flow;
4858 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004859
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004860 // Get rid of all references to package scan path via parser.
4861 pp = null;
4862 String oldCodePath = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004863 synchronized (mPackages) {
4864 //check if installing already existing package
Dianne Hackbornade3eca2009-05-11 18:54:45 -07004865 if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004866 && mPackages.containsKey(pkgName)) {
4867 replacingExistingPackage = true;
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004868 }
4869 PackageSetting ps = mSettings.mPackages.get(pkgName);
4870 if (ps != null) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004871 oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004872 }
4873 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004874
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004875 if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
4876 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
4877 break main_flow;
4878 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004879 // Set application objects path explicitly after the rename
4880 setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004881 if(replacingExistingPackage) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004882 replacePackageLI(pkg, parseFlags, scanMode,
4883 installerPackageName, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004884 } else {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004885 installNewPackageLI(pkg, parseFlags, scanMode,
4886 installerPackageName,res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004887 }
4888 } finally {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004889 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004891 }
4892 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004893
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004894 private int setPermissionsLI(PackageParser.Package newPackage) {
4895 String pkgName = newPackage.packageName;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004896 int retCode = 0;
4897 // TODO Gross hack but fix later. Ideally move this to be a post installation
4898 // check after alloting uid.
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004899 if ((newPackage.applicationInfo.flags
4900 & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
4901 File destResourceFile = new File(newPackage.applicationInfo.publicSourceDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004902 try {
4903 extractPublicFiles(newPackage, destResourceFile);
4904 } catch (IOException e) {
4905 Log.e(TAG, "Couldn't create a new zip file for the public parts of a" +
4906 " forward-locked app.");
4907 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
4908 } finally {
4909 //TODO clean up the extracted public files
4910 }
4911 if (mInstaller != null) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004912 retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004913 newPackage.applicationInfo.uid);
4914 } else {
4915 final int filePermissions =
4916 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004917 retCode = FileUtils.setPermissions(newPackage.mPath, filePermissions, -1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004918 newPackage.applicationInfo.uid);
4919 }
4920 } else {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004921 // The permissions on the resource file was set when it was copied for
4922 // non forward locked apps and apps on sdcard
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004923 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004924
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004925 if (retCode != 0) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004926 Log.e(TAG, "Couldn't set new package file permissions for " +
4927 newPackage.mPath
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004928 + ". The return code was: " + retCode);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08004929 // TODO Define new internal error
4930 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004931 }
4932 return PackageManager.INSTALL_SUCCEEDED;
4933 }
4934
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08004935 private boolean isForwardLocked(PackageParser.Package pkg) {
4936 return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004937 }
4938
4939 private void extractPublicFiles(PackageParser.Package newPackage,
4940 File publicZipFile) throws IOException {
4941 final ZipOutputStream publicZipOutStream =
4942 new ZipOutputStream(new FileOutputStream(publicZipFile));
4943 final ZipFile privateZip = new ZipFile(newPackage.mPath);
4944
4945 // Copy manifest, resources.arsc and res directory to public zip
4946
4947 final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
4948 while (privateZipEntries.hasMoreElements()) {
4949 final ZipEntry zipEntry = privateZipEntries.nextElement();
4950 final String zipEntryName = zipEntry.getName();
4951 if ("AndroidManifest.xml".equals(zipEntryName)
4952 || "resources.arsc".equals(zipEntryName)
4953 || zipEntryName.startsWith("res/")) {
4954 try {
4955 copyZipEntry(zipEntry, privateZip, publicZipOutStream);
4956 } catch (IOException e) {
4957 try {
4958 publicZipOutStream.close();
4959 throw e;
4960 } finally {
4961 publicZipFile.delete();
4962 }
4963 }
4964 }
4965 }
4966
4967 publicZipOutStream.close();
4968 FileUtils.setPermissions(
4969 publicZipFile.getAbsolutePath(),
4970 FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP|FileUtils.S_IROTH,
4971 -1, -1);
4972 }
4973
4974 private static void copyZipEntry(ZipEntry zipEntry,
4975 ZipFile inZipFile,
4976 ZipOutputStream outZipStream) throws IOException {
4977 byte[] buffer = new byte[4096];
4978 int num;
4979
4980 ZipEntry newEntry;
4981 if (zipEntry.getMethod() == ZipEntry.STORED) {
4982 // Preserve the STORED method of the input entry.
4983 newEntry = new ZipEntry(zipEntry);
4984 } else {
4985 // Create a new entry so that the compressed len is recomputed.
4986 newEntry = new ZipEntry(zipEntry.getName());
4987 }
4988 outZipStream.putNextEntry(newEntry);
4989
4990 InputStream data = inZipFile.getInputStream(zipEntry);
4991 while ((num = data.read(buffer)) > 0) {
4992 outZipStream.write(buffer, 0, num);
4993 }
4994 outZipStream.flush();
4995 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004997 private void deleteTempPackageFiles() {
4998 FilenameFilter filter = new FilenameFilter() {
4999 public boolean accept(File dir, String name) {
5000 return name.startsWith("vmdl") && name.endsWith(".tmp");
5001 }
5002 };
5003 String tmpFilesList[] = mAppInstallDir.list(filter);
5004 if(tmpFilesList == null) {
5005 return;
5006 }
5007 for(int i = 0; i < tmpFilesList.length; i++) {
5008 File tmpFile = new File(mAppInstallDir, tmpFilesList[i]);
5009 tmpFile.delete();
5010 }
5011 }
5012
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08005013 private File createTempPackageFile(File installDir) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005014 File tmpPackageFile;
5015 try {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08005016 tmpPackageFile = File.createTempFile("vmdl", ".tmp", installDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005017 } catch (IOException e) {
5018 Log.e(TAG, "Couldn't create temp file for downloaded package file.");
5019 return null;
5020 }
5021 try {
5022 FileUtils.setPermissions(
5023 tmpPackageFile.getCanonicalPath(), FileUtils.S_IRUSR|FileUtils.S_IWUSR,
5024 -1, -1);
5025 } catch (IOException e) {
5026 Log.e(TAG, "Trouble getting the canoncical path for a temp file.");
5027 return null;
5028 }
5029 return tmpPackageFile;
5030 }
5031
5032 public void deletePackage(final String packageName,
5033 final IPackageDeleteObserver observer,
5034 final int flags) {
5035 mContext.enforceCallingOrSelfPermission(
5036 android.Manifest.permission.DELETE_PACKAGES, null);
5037 // Queue up an async operation since the package deletion may take a little while.
5038 mHandler.post(new Runnable() {
5039 public void run() {
5040 mHandler.removeCallbacks(this);
5041 final boolean succeded = deletePackageX(packageName, true, true, flags);
5042 if (observer != null) {
5043 try {
5044 observer.packageDeleted(succeded);
5045 } catch (RemoteException e) {
5046 Log.i(TAG, "Observer no longer exists.");
5047 } //end catch
5048 } //end if
5049 } //end run
5050 });
5051 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005053 /**
5054 * This method is an internal method that could be get invoked either
5055 * to delete an installed package or to clean up a failed installation.
5056 * After deleting an installed package, a broadcast is sent to notify any
5057 * listeners that the package has been installed. For cleaning up a failed
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005058 * installation, the broadcast is not necessary since the package's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005059 * installation wouldn't have sent the initial broadcast either
5060 * The key steps in deleting a package are
5061 * deleting the package information in internal structures like mPackages,
5062 * deleting the packages base directories through installd
5063 * updating mSettings to reflect current status
5064 * persisting settings for later use
5065 * sending a broadcast if necessary
5066 */
5067
5068 private boolean deletePackageX(String packageName, boolean sendBroadCast,
5069 boolean deleteCodeAndResources, int flags) {
5070 PackageRemovedInfo info = new PackageRemovedInfo();
Romain Guy96f43572009-03-24 20:27:49 -07005071 boolean res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005072
5073 synchronized (mInstallLock) {
5074 res = deletePackageLI(packageName, deleteCodeAndResources, flags, info);
5075 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005077 if(res && sendBroadCast) {
Romain Guy96f43572009-03-24 20:27:49 -07005078 boolean systemUpdate = info.isRemovedPackageSystemUpdate;
5079 info.sendBroadcast(deleteCodeAndResources, systemUpdate);
5080
5081 // If the removed package was a system update, the old system packaged
5082 // was re-enabled; we need to broadcast this information
5083 if (systemUpdate) {
5084 Bundle extras = new Bundle(1);
5085 extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
5086 extras.putBoolean(Intent.EXTRA_REPLACING, true);
5087
5088 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras);
5089 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras);
5090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005091 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08005092 // Delete the resources here after sending the broadcast to let
5093 // other processes clean up before deleting resources.
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005094 if (info.args != null) {
5095 synchronized (mInstallLock) {
5096 info.args.doPostDeleteLI(deleteCodeAndResources);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08005097 }
5098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005099 return res;
5100 }
5101
5102 static class PackageRemovedInfo {
5103 String removedPackage;
5104 int uid = -1;
5105 int removedUid = -1;
Romain Guy96f43572009-03-24 20:27:49 -07005106 boolean isRemovedPackageSystemUpdate = false;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08005107 // Clean up resources deleted packages.
5108 InstallArgs args = null;
Romain Guy96f43572009-03-24 20:27:49 -07005109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005110 void sendBroadcast(boolean fullRemove, boolean replacing) {
5111 Bundle extras = new Bundle(1);
5112 extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid);
5113 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
5114 if (replacing) {
5115 extras.putBoolean(Intent.EXTRA_REPLACING, true);
5116 }
5117 if (removedPackage != null) {
5118 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
5119 }
5120 if (removedUid >= 0) {
5121 sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras);
5122 }
5123 }
5124 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005126 /*
5127 * This method deletes the package from internal data structures. If the DONT_DELETE_DATA
5128 * flag is not set, the data directory is removed as well.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005129 * make sure this flag is set for partially installed apps. If not its meaningless to
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005130 * delete a partially installed application.
5131 */
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005132 private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005133 int flags) {
5134 String packageName = p.packageName;
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07005135 if (outInfo != null) {
5136 outInfo.removedPackage = packageName;
5137 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005138 removePackageLI(p, true);
5139 // Retrieve object to delete permissions for shared user later on
5140 PackageSetting deletedPs;
5141 synchronized (mPackages) {
5142 deletedPs = mSettings.mPackages.get(packageName);
5143 }
5144 if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08005145 boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005146 if (mInstaller != null) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08005147 int retCode = mInstaller.remove(packageName, useEncryptedFSDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005148 if (retCode < 0) {
5149 Log.w(TAG, "Couldn't remove app data or cache directory for package: "
5150 + packageName + ", retcode=" + retCode);
5151 // we don't consider this to be a failure of the core package deletion
5152 }
5153 } else {
5154 //for emulator
5155 PackageParser.Package pkg = mPackages.get(packageName);
5156 File dataDir = new File(pkg.applicationInfo.dataDir);
5157 dataDir.delete();
5158 }
5159 synchronized (mPackages) {
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07005160 if (outInfo != null) {
5161 outInfo.removedUid = mSettings.removePackageLP(packageName);
5162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005163 }
5164 }
5165 synchronized (mPackages) {
5166 if ( (deletedPs != null) && (deletedPs.sharedUser != null)) {
5167 // remove permissions associated with package
Suchi Amalapurapu2ed287b2009-08-05 12:43:00 -07005168 mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005169 }
5170 // Save settings now
5171 mSettings.writeLP ();
5172 }
5173 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005175 /*
5176 * Tries to delete system package.
5177 */
5178 private boolean deleteSystemPackageLI(PackageParser.Package p,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005179 int flags, PackageRemovedInfo outInfo) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005180 ApplicationInfo applicationInfo = p.applicationInfo;
5181 //applicable for non-partially installed applications only
5182 if (applicationInfo == null) {
5183 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
5184 return false;
5185 }
5186 PackageSetting ps = null;
5187 // Confirm if the system package has been updated
5188 // An updated system app can be deleted. This will also have to restore
5189 // the system pkg from system partition
5190 synchronized (mPackages) {
5191 ps = mSettings.getDisabledSystemPkg(p.packageName);
5192 }
5193 if (ps == null) {
5194 Log.w(TAG, "Attempt to delete system package "+ p.packageName);
5195 return false;
5196 } else {
5197 Log.i(TAG, "Deleting system pkg from data partition");
5198 }
5199 // Delete the updated package
Romain Guy96f43572009-03-24 20:27:49 -07005200 outInfo.isRemovedPackageSystemUpdate = true;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005201 boolean deleteCodeAndResources = false;
5202 if (ps.versionCode < p.mVersionCode) {
5203 // Delete code and resources for downgrades
5204 deleteCodeAndResources = true;
5205 if ((flags & PackageManager.DONT_DELETE_DATA) == 0) {
5206 flags &= ~PackageManager.DONT_DELETE_DATA;
5207 }
5208 } else {
5209 // Preserve data by setting flag
5210 if ((flags & PackageManager.DONT_DELETE_DATA) == 0) {
5211 flags |= PackageManager.DONT_DELETE_DATA;
5212 }
5213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005214 boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo);
5215 if (!ret) {
5216 return false;
5217 }
5218 synchronized (mPackages) {
5219 // Reinstate the old system package
5220 mSettings.enableSystemPackageLP(p.packageName);
5221 }
5222 // Install the system package
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08005223 PackageParser.Package newPkg = scanPackageLI(ps.codePath,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005224 PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08005225 SCAN_MONITOR | SCAN_NO_PATHS);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005227 if (newPkg == null) {
5228 Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
5229 return false;
5230 }
5231 synchronized (mPackages) {
Suchi Amalapurapu701f5162009-06-03 15:47:55 -07005232 grantPermissionsLP(newPkg, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 mSettings.writeLP();
5234 }
5235 return true;
5236 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07005237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005238 private boolean deleteInstalledPackageLI(PackageParser.Package p,
5239 boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
5240 ApplicationInfo applicationInfo = p.applicationInfo;
5241 if (applicationInfo == null) {
5242 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
5243 return false;
5244 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07005245 if (outInfo != null) {
5246 outInfo.uid = applicationInfo.uid;
5247 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005248
5249 // Delete package data from internal structures and also remove data if flag is set
5250 removePackageDataLI(p, outInfo, flags);
5251
5252 // Delete application code and resources
5253 if (deleteCodeAndResources) {
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08005254 // TODO can pick up from PackageSettings as well
5255 int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD)!=0) ?
5256 PackageManager.INSTALL_ON_SDCARD : 0;
5257 installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ?
5258 PackageManager.INSTALL_FORWARD_LOCK : 0;
5259 outInfo.args = createInstallArgs(installFlags,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07005260 applicationInfo.sourceDir, applicationInfo.publicSourceDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005261 }
5262 return true;
5263 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265 /*
5266 * This method handles package deletion in general
5267 */
5268 private boolean deletePackageLI(String packageName,
5269 boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
5270 if (packageName == null) {
5271 Log.w(TAG, "Attempt to delete null packageName.");
5272 return false;
5273 }
5274 PackageParser.Package p;
5275 boolean dataOnly = false;
5276 synchronized (mPackages) {
5277 p = mPackages.get(packageName);
5278 if (p == null) {
5279 //this retrieves partially installed apps
5280 dataOnly = true;
5281 PackageSetting ps = mSettings.mPackages.get(packageName);
5282 if (ps == null) {
5283 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
5284 return false;
5285 }
5286 p = ps.pkg;
5287 }
5288 }
5289 if (p == null) {
5290 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
5291 return false;
5292 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005294 if (dataOnly) {
5295 // Delete application data first
5296 removePackageDataLI(p, outInfo, flags);
5297 return true;
5298 }
5299 // At this point the package should have ApplicationInfo associated with it
5300 if (p.applicationInfo == null) {
5301 Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
5302 return false;
5303 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08005304 boolean ret = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005305 if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
5306 Log.i(TAG, "Removing system package:"+p.packageName);
5307 // When an updated system application is deleted we delete the existing resources as well and
5308 // fall back to existing code in system partition
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08005309 ret = deleteSystemPackageLI(p, flags, outInfo);
5310 } else {
5311 Log.i(TAG, "Removing non-system package:"+p.packageName);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08005312 // Kill application pre-emptively especially for apps on sd.
5313 killApplication(packageName, p.applicationInfo.uid);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08005314 ret = deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005315 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08005316 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005317 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005319 public void clearApplicationUserData(final String packageName,
5320 final IPackageDataObserver observer) {
5321 mContext.enforceCallingOrSelfPermission(
5322 android.Manifest.permission.CLEAR_APP_USER_DATA, null);
5323 // Queue up an async operation since the package deletion may take a little while.
5324 mHandler.post(new Runnable() {
5325 public void run() {
5326 mHandler.removeCallbacks(this);
5327 final boolean succeeded;
5328 synchronized (mInstallLock) {
5329 succeeded = clearApplicationUserDataLI(packageName);
5330 }
5331 if (succeeded) {
5332 // invoke DeviceStorageMonitor's update method to clear any notifications
5333 DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
5334 ServiceManager.getService(DeviceStorageMonitorService.SERVICE);
5335 if (dsm != null) {
5336 dsm.updateMemory();
5337 }
5338 }
5339 if(observer != null) {
5340 try {
5341 observer.onRemoveCompleted(packageName, succeeded);
5342 } catch (RemoteException e) {
5343 Log.i(TAG, "Observer no longer exists.");
5344 }
5345 } //end if observer
5346 } //end run
5347 });
5348 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005350 private boolean clearApplicationUserDataLI(String packageName) {
5351 if (packageName == null) {
5352 Log.w(TAG, "Attempt to delete null packageName.");
5353 return false;
5354 }
5355 PackageParser.Package p;
5356 boolean dataOnly = false;
5357 synchronized (mPackages) {
5358 p = mPackages.get(packageName);
5359 if(p == null) {
5360 dataOnly = true;
5361 PackageSetting ps = mSettings.mPackages.get(packageName);
5362 if((ps == null) || (ps.pkg == null)) {
5363 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
5364 return false;
5365 }
5366 p = ps.pkg;
5367 }
5368 }
Oscar Montemayora8529f62009-11-18 10:14:20 -08005369 boolean useEncryptedFSDir = false;
5370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005371 if(!dataOnly) {
5372 //need to check this only for fully installed applications
5373 if (p == null) {
5374 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
5375 return false;
5376 }
5377 final ApplicationInfo applicationInfo = p.applicationInfo;
5378 if (applicationInfo == null) {
5379 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
5380 return false;
5381 }
Oscar Montemayora8529f62009-11-18 10:14:20 -08005382 useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005383 }
5384 if (mInstaller != null) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08005385 int retCode = mInstaller.clearUserData(packageName, useEncryptedFSDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005386 if (retCode < 0) {
5387 Log.w(TAG, "Couldn't remove cache files for package: "
5388 + packageName);
5389 return false;
5390 }
5391 }
5392 return true;
5393 }
5394
5395 public void deleteApplicationCacheFiles(final String packageName,
5396 final IPackageDataObserver observer) {
5397 mContext.enforceCallingOrSelfPermission(
5398 android.Manifest.permission.DELETE_CACHE_FILES, null);
5399 // Queue up an async operation since the package deletion may take a little while.
5400 mHandler.post(new Runnable() {
5401 public void run() {
5402 mHandler.removeCallbacks(this);
5403 final boolean succeded;
5404 synchronized (mInstallLock) {
5405 succeded = deleteApplicationCacheFilesLI(packageName);
5406 }
5407 if(observer != null) {
5408 try {
5409 observer.onRemoveCompleted(packageName, succeded);
5410 } catch (RemoteException e) {
5411 Log.i(TAG, "Observer no longer exists.");
5412 }
5413 } //end if observer
5414 } //end run
5415 });
5416 }
5417
5418 private boolean deleteApplicationCacheFilesLI(String packageName) {
5419 if (packageName == null) {
5420 Log.w(TAG, "Attempt to delete null packageName.");
5421 return false;
5422 }
5423 PackageParser.Package p;
5424 synchronized (mPackages) {
5425 p = mPackages.get(packageName);
5426 }
5427 if (p == null) {
5428 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
5429 return false;
5430 }
5431 final ApplicationInfo applicationInfo = p.applicationInfo;
5432 if (applicationInfo == null) {
5433 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
5434 return false;
5435 }
Oscar Montemayora8529f62009-11-18 10:14:20 -08005436 boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005437 if (mInstaller != null) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08005438 int retCode = mInstaller.deleteCacheFiles(packageName, useEncryptedFSDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005439 if (retCode < 0) {
5440 Log.w(TAG, "Couldn't remove cache files for package: "
5441 + packageName);
5442 return false;
5443 }
5444 }
5445 return true;
5446 }
5447
5448 public void getPackageSizeInfo(final String packageName,
5449 final IPackageStatsObserver observer) {
5450 mContext.enforceCallingOrSelfPermission(
5451 android.Manifest.permission.GET_PACKAGE_SIZE, null);
5452 // Queue up an async operation since the package deletion may take a little while.
5453 mHandler.post(new Runnable() {
5454 public void run() {
5455 mHandler.removeCallbacks(this);
5456 PackageStats lStats = new PackageStats(packageName);
5457 final boolean succeded;
5458 synchronized (mInstallLock) {
5459 succeded = getPackageSizeInfoLI(packageName, lStats);
5460 }
5461 if(observer != null) {
5462 try {
5463 observer.onGetStatsCompleted(lStats, succeded);
5464 } catch (RemoteException e) {
5465 Log.i(TAG, "Observer no longer exists.");
5466 }
5467 } //end if observer
5468 } //end run
5469 });
5470 }
5471
5472 private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) {
5473 if (packageName == null) {
5474 Log.w(TAG, "Attempt to get size of null packageName.");
5475 return false;
5476 }
5477 PackageParser.Package p;
5478 boolean dataOnly = false;
5479 synchronized (mPackages) {
5480 p = mPackages.get(packageName);
5481 if(p == null) {
5482 dataOnly = true;
5483 PackageSetting ps = mSettings.mPackages.get(packageName);
5484 if((ps == null) || (ps.pkg == null)) {
5485 Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
5486 return false;
5487 }
5488 p = ps.pkg;
5489 }
5490 }
5491 String publicSrcDir = null;
5492 if(!dataOnly) {
5493 final ApplicationInfo applicationInfo = p.applicationInfo;
5494 if (applicationInfo == null) {
5495 Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
5496 return false;
5497 }
5498 publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
5499 }
Oscar Montemayora8529f62009-11-18 10:14:20 -08005500 boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005501 if (mInstaller != null) {
5502 int res = mInstaller.getSizeInfo(packageName, p.mPath,
Oscar Montemayora8529f62009-11-18 10:14:20 -08005503 publicSrcDir, pStats, useEncryptedFSDir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005504 if (res < 0) {
5505 return false;
5506 } else {
5507 return true;
5508 }
5509 }
5510 return true;
5511 }
5512
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005514 public void addPackageToPreferred(String packageName) {
5515 mContext.enforceCallingOrSelfPermission(
5516 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
Dianne Hackborna7ca0e52009-12-01 14:31:55 -08005517 Log.w(TAG, "addPackageToPreferred: no longer implemented");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005518 }
5519
5520 public void removePackageFromPreferred(String packageName) {
5521 mContext.enforceCallingOrSelfPermission(
5522 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
Dianne Hackborna7ca0e52009-12-01 14:31:55 -08005523 Log.w(TAG, "removePackageFromPreferred: no longer implemented");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005524 }
5525
5526 public List<PackageInfo> getPreferredPackages(int flags) {
Dianne Hackborna7ca0e52009-12-01 14:31:55 -08005527 return new ArrayList<PackageInfo>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005528 }
5529
5530 public void addPreferredActivity(IntentFilter filter, int match,
5531 ComponentName[] set, ComponentName activity) {
5532 mContext.enforceCallingOrSelfPermission(
5533 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
5534
5535 synchronized (mPackages) {
5536 Log.i(TAG, "Adding preferred activity " + activity + ":");
5537 filter.dump(new LogPrinter(Log.INFO, TAG), " ");
5538 mSettings.mPreferredActivities.addFilter(
5539 new PreferredActivity(filter, match, set, activity));
5540 mSettings.writeLP();
5541 }
5542 }
5543
Satish Sampath8dbe6122009-06-02 23:35:54 +01005544 public void replacePreferredActivity(IntentFilter filter, int match,
5545 ComponentName[] set, ComponentName activity) {
5546 mContext.enforceCallingOrSelfPermission(
5547 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
5548 if (filter.countActions() != 1) {
5549 throw new IllegalArgumentException(
5550 "replacePreferredActivity expects filter to have only 1 action.");
5551 }
5552 if (filter.countCategories() != 1) {
5553 throw new IllegalArgumentException(
5554 "replacePreferredActivity expects filter to have only 1 category.");
5555 }
5556 if (filter.countDataAuthorities() != 0
5557 || filter.countDataPaths() != 0
5558 || filter.countDataSchemes() != 0
5559 || filter.countDataTypes() != 0) {
5560 throw new IllegalArgumentException(
5561 "replacePreferredActivity expects filter to have no data authorities, " +
5562 "paths, schemes or types.");
5563 }
5564 synchronized (mPackages) {
5565 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
5566 String action = filter.getAction(0);
5567 String category = filter.getCategory(0);
5568 while (it.hasNext()) {
5569 PreferredActivity pa = it.next();
5570 if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
5571 it.remove();
5572 Log.i(TAG, "Removed preferred activity " + pa.mActivity + ":");
5573 filter.dump(new LogPrinter(Log.INFO, TAG), " ");
5574 }
5575 }
5576 addPreferredActivity(filter, match, set, activity);
5577 }
5578 }
5579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005580 public void clearPackagePreferredActivities(String packageName) {
5581 mContext.enforceCallingOrSelfPermission(
5582 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
5583
5584 synchronized (mPackages) {
5585 if (clearPackagePreferredActivitiesLP(packageName)) {
5586 mSettings.writeLP();
5587 }
5588 }
5589 }
5590
5591 boolean clearPackagePreferredActivitiesLP(String packageName) {
5592 boolean changed = false;
5593 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
5594 while (it.hasNext()) {
5595 PreferredActivity pa = it.next();
5596 if (pa.mActivity.getPackageName().equals(packageName)) {
5597 it.remove();
5598 changed = true;
5599 }
5600 }
5601 return changed;
5602 }
5603
5604 public int getPreferredActivities(List<IntentFilter> outFilters,
5605 List<ComponentName> outActivities, String packageName) {
5606
5607 int num = 0;
5608 synchronized (mPackages) {
5609 Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
5610 while (it.hasNext()) {
5611 PreferredActivity pa = it.next();
5612 if (packageName == null
5613 || pa.mActivity.getPackageName().equals(packageName)) {
5614 if (outFilters != null) {
5615 outFilters.add(new IntentFilter(pa));
5616 }
5617 if (outActivities != null) {
5618 outActivities.add(pa.mActivity);
5619 }
5620 }
5621 }
5622 }
5623
5624 return num;
5625 }
5626
5627 public void setApplicationEnabledSetting(String appPackageName,
5628 int newState, int flags) {
5629 setEnabledSetting(appPackageName, null, newState, flags);
5630 }
5631
5632 public void setComponentEnabledSetting(ComponentName componentName,
5633 int newState, int flags) {
5634 setEnabledSetting(componentName.getPackageName(),
5635 componentName.getClassName(), newState, flags);
5636 }
5637
5638 private void setEnabledSetting(
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005639 final String packageName, String className, int newState, final int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005640 if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
5641 || newState == COMPONENT_ENABLED_STATE_ENABLED
5642 || newState == COMPONENT_ENABLED_STATE_DISABLED)) {
5643 throw new IllegalArgumentException("Invalid new component state: "
5644 + newState);
5645 }
5646 PackageSetting pkgSetting;
5647 final int uid = Binder.getCallingUid();
5648 final int permission = mContext.checkCallingPermission(
5649 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
5650 final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005651 boolean sendNow = false;
5652 boolean isApp = (className == null);
Dianne Hackborn86a72da2009-11-11 20:12:41 -08005653 String componentName = isApp ? packageName : className;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005654 int packageUid = -1;
Dianne Hackborn86a72da2009-11-11 20:12:41 -08005655 ArrayList<String> components;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005656 synchronized (mPackages) {
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005657 pkgSetting = mSettings.mPackages.get(packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005658 if (pkgSetting == null) {
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005659 if (className == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005660 throw new IllegalArgumentException(
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005661 "Unknown package: " + packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005662 }
5663 throw new IllegalArgumentException(
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005664 "Unknown component: " + packageName
5665 + "/" + className);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005666 }
5667 if (!allowedByPermission && (uid != pkgSetting.userId)) {
5668 throw new SecurityException(
5669 "Permission Denial: attempt to change component state from pid="
5670 + Binder.getCallingPid()
5671 + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
5672 }
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005673 if (className == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005674 // We're dealing with an application/package level state change
5675 pkgSetting.enabled = newState;
5676 } else {
5677 // We're dealing with a component level state change
5678 switch (newState) {
5679 case COMPONENT_ENABLED_STATE_ENABLED:
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005680 pkgSetting.enableComponentLP(className);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005681 break;
5682 case COMPONENT_ENABLED_STATE_DISABLED:
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005683 pkgSetting.disableComponentLP(className);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005684 break;
5685 case COMPONENT_ENABLED_STATE_DEFAULT:
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005686 pkgSetting.restoreComponentLP(className);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005687 break;
5688 default:
5689 Log.e(TAG, "Invalid new component state: " + newState);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005690 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005691 }
5692 }
5693 mSettings.writeLP();
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005694 packageUid = pkgSetting.userId;
Dianne Hackborn86a72da2009-11-11 20:12:41 -08005695 components = mPendingBroadcasts.get(packageName);
5696 boolean newPackage = components == null;
5697 if (newPackage) {
5698 components = new ArrayList<String>();
5699 }
5700 if (!components.contains(componentName)) {
5701 components.add(componentName);
5702 }
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005703 if ((flags&PackageManager.DONT_KILL_APP) == 0) {
5704 sendNow = true;
5705 // Purge entry from pending broadcast list if another one exists already
5706 // since we are sending one right away.
Dianne Hackborn86a72da2009-11-11 20:12:41 -08005707 mPendingBroadcasts.remove(packageName);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005708 } else {
Dianne Hackborn86a72da2009-11-11 20:12:41 -08005709 if (newPackage) {
5710 mPendingBroadcasts.put(packageName, components);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005711 }
5712 if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
5713 // Schedule a message
5714 mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
5715 }
5716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005717 }
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005719 long callingId = Binder.clearCallingIdentity();
5720 try {
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005721 if (sendNow) {
5722 sendPackageChangedBroadcast(packageName,
Dianne Hackborn86a72da2009-11-11 20:12:41 -08005723 (flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005724 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005725 } finally {
5726 Binder.restoreCallingIdentity(callingId);
5727 }
5728 }
5729
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005730 private void sendPackageChangedBroadcast(String packageName,
Dianne Hackborn86a72da2009-11-11 20:12:41 -08005731 boolean killFlag, ArrayList<String> componentNames, int packageUid) {
5732 if (false) Log.v(TAG, "Sending package changed: package=" + packageName
5733 + " components=" + componentNames);
5734 Bundle extras = new Bundle(4);
5735 extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
5736 String nameList[] = new String[componentNames.size()];
5737 componentNames.toArray(nameList);
5738 extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005739 extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
5740 extras.putInt(Intent.EXTRA_UID, packageUid);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005741 sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras);
Suchi Amalapurapu0214e942009-09-02 11:03:18 -07005742 }
5743
Jacek Surazski65e13172009-04-28 15:26:38 +02005744 public String getInstallerPackageName(String packageName) {
5745 synchronized (mPackages) {
5746 PackageSetting pkg = mSettings.mPackages.get(packageName);
5747 if (pkg == null) {
5748 throw new IllegalArgumentException("Unknown package: " + packageName);
5749 }
5750 return pkg.installerPackageName;
5751 }
5752 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005754 public int getApplicationEnabledSetting(String appPackageName) {
5755 synchronized (mPackages) {
5756 PackageSetting pkg = mSettings.mPackages.get(appPackageName);
5757 if (pkg == null) {
5758 throw new IllegalArgumentException("Unknown package: " + appPackageName);
5759 }
5760 return pkg.enabled;
5761 }
5762 }
5763
5764 public int getComponentEnabledSetting(ComponentName componentName) {
5765 synchronized (mPackages) {
5766 final String packageNameStr = componentName.getPackageName();
5767 PackageSetting pkg = mSettings.mPackages.get(packageNameStr);
5768 if (pkg == null) {
5769 throw new IllegalArgumentException("Unknown component: " + componentName);
5770 }
5771 final String classNameStr = componentName.getClassName();
5772 return pkg.currentEnabledStateLP(classNameStr);
5773 }
5774 }
5775
5776 public void enterSafeMode() {
5777 if (!mSystemReady) {
5778 mSafeMode = true;
5779 }
5780 }
5781
5782 public void systemReady() {
5783 mSystemReady = true;
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005784
5785 // Read the compatibilty setting when the system is ready.
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07005786 boolean compatibilityModeEnabled = android.provider.Settings.System.getInt(
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005787 mContext.getContentResolver(),
5788 android.provider.Settings.System.COMPATIBILITY_MODE, 1) == 1;
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07005789 PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005790 if (DEBUG_SETTINGS) {
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07005791 Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005793 }
5794
5795 public boolean isSafeMode() {
5796 return mSafeMode;
5797 }
5798
5799 public boolean hasSystemUidErrors() {
5800 return mHasSystemUidErrors;
5801 }
5802
5803 static String arrayToString(int[] array) {
5804 StringBuffer buf = new StringBuffer(128);
5805 buf.append('[');
5806 if (array != null) {
5807 for (int i=0; i<array.length; i++) {
5808 if (i > 0) buf.append(", ");
5809 buf.append(array[i]);
5810 }
5811 }
5812 buf.append(']');
5813 return buf.toString();
5814 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005815
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005816 @Override
5817 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5818 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
5819 != PackageManager.PERMISSION_GRANTED) {
5820 pw.println("Permission Denial: can't dump ActivityManager from from pid="
5821 + Binder.getCallingPid()
5822 + ", uid=" + Binder.getCallingUid()
5823 + " without permission "
5824 + android.Manifest.permission.DUMP);
5825 return;
5826 }
5827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005828 synchronized (mPackages) {
5829 pw.println("Activity Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005830 mActivities.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005831 pw.println(" ");
5832 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005833 mReceivers.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005834 pw.println(" ");
5835 pw.println("Service Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005836 mServices.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005837 pw.println(" ");
5838 pw.println("Preferred Activities:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005839 mSettings.mPreferredActivities.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005840 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005841 pw.println("Permissions:");
5842 {
5843 for (BasePermission p : mSettings.mPermissions.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005844 pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
5845 pw.print(Integer.toHexString(System.identityHashCode(p)));
5846 pw.println("):");
5847 pw.print(" sourcePackage="); pw.println(p.sourcePackage);
5848 pw.print(" uid="); pw.print(p.uid);
5849 pw.print(" gids="); pw.print(arrayToString(p.gids));
5850 pw.print(" type="); pw.println(p.type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005851 }
5852 }
5853 pw.println(" ");
5854 pw.println("Packages:");
5855 {
5856 for (PackageSetting ps : mSettings.mPackages.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005857 pw.print(" Package ["); pw.print(ps.name); pw.print("] (");
5858 pw.print(Integer.toHexString(System.identityHashCode(ps)));
5859 pw.println("):");
5860 pw.print(" userId="); pw.print(ps.userId);
5861 pw.print(" gids="); pw.println(arrayToString(ps.gids));
5862 pw.print(" sharedUser="); pw.println(ps.sharedUser);
5863 pw.print(" pkg="); pw.println(ps.pkg);
5864 pw.print(" codePath="); pw.println(ps.codePathString);
5865 pw.print(" resourcePath="); pw.println(ps.resourcePathString);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005866 if (ps.pkg != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005867 pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
Mitsuru Oshima841f13c2009-07-17 17:23:31 -07005868 pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
Dianne Hackborn11b822d2009-07-21 20:03:02 -07005869 pw.print(" supportsScreens=[");
5870 boolean first = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005871 if ((ps.pkg.applicationInfo.flags &
Mitsuru Oshima841f13c2009-07-17 17:23:31 -07005872 ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
Dianne Hackborn11b822d2009-07-21 20:03:02 -07005873 if (!first) pw.print(", ");
5874 first = false;
5875 pw.print("medium");
Mitsuru Oshima841f13c2009-07-17 17:23:31 -07005876 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005877 if ((ps.pkg.applicationInfo.flags &
Mitsuru Oshima841f13c2009-07-17 17:23:31 -07005878 ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
Dianne Hackborn11b822d2009-07-21 20:03:02 -07005879 if (!first) pw.print(", ");
5880 first = false;
5881 pw.print("large");
Mitsuru Oshima841f13c2009-07-17 17:23:31 -07005882 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005883 if ((ps.pkg.applicationInfo.flags &
Mitsuru Oshima841f13c2009-07-17 17:23:31 -07005884 ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
Dianne Hackborn11b822d2009-07-21 20:03:02 -07005885 if (!first) pw.print(", ");
5886 first = false;
5887 pw.print("small");
Mitsuru Oshima841f13c2009-07-17 17:23:31 -07005888 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005889 if ((ps.pkg.applicationInfo.flags &
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07005890 ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
Dianne Hackborn11b822d2009-07-21 20:03:02 -07005891 if (!first) pw.print(", ");
5892 first = false;
5893 pw.print("resizeable");
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07005894 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005895 if ((ps.pkg.applicationInfo.flags &
Dianne Hackborn11b822d2009-07-21 20:03:02 -07005896 ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
5897 if (!first) pw.print(", ");
5898 first = false;
5899 pw.print("anyDensity");
5900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005901 }
Dianne Hackborn11b822d2009-07-21 20:03:02 -07005902 pw.println("]");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005903 pw.print(" timeStamp="); pw.println(ps.getTimeStampStr());
5904 pw.print(" signatures="); pw.println(ps.signatures);
5905 pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
5906 pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
5907 pw.print(" installStatus="); pw.print(ps.installStatus);
5908 pw.print(" enabled="); pw.println(ps.enabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005909 if (ps.disabledComponents.size() > 0) {
5910 pw.println(" disabledComponents:");
5911 for (String s : ps.disabledComponents) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005912 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005913 }
5914 }
5915 if (ps.enabledComponents.size() > 0) {
5916 pw.println(" enabledComponents:");
5917 for (String s : ps.enabledComponents) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005918 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005919 }
5920 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005921 if (ps.grantedPermissions.size() > 0) {
5922 pw.println(" grantedPermissions:");
5923 for (String s : ps.grantedPermissions) {
5924 pw.print(" "); pw.println(s);
5925 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005926 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005927 if (ps.loadedPermissions.size() > 0) {
5928 pw.println(" loadedPermissions:");
5929 for (String s : ps.loadedPermissions) {
5930 pw.print(" "); pw.println(s);
5931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005932 }
5933 }
5934 }
5935 pw.println(" ");
5936 pw.println("Shared Users:");
5937 {
5938 for (SharedUserSetting su : mSettings.mSharedUsers.values()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005939 pw.print(" SharedUser ["); pw.print(su.name); pw.print("] (");
5940 pw.print(Integer.toHexString(System.identityHashCode(su)));
5941 pw.println("):");
5942 pw.print(" userId="); pw.print(su.userId);
5943 pw.print(" gids="); pw.println(arrayToString(su.gids));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005944 pw.println(" grantedPermissions:");
5945 for (String s : su.grantedPermissions) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005946 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005947 }
5948 pw.println(" loadedPermissions:");
5949 for (String s : su.loadedPermissions) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005950 pw.print(" "); pw.println(s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005951 }
5952 }
5953 }
5954 pw.println(" ");
5955 pw.println("Settings parse messages:");
5956 pw.println(mSettings.mReadMessages.toString());
5957 }
Jeff Hamilton5bfc64f2009-08-18 12:25:30 -05005958
5959 synchronized (mProviders) {
5960 pw.println(" ");
5961 pw.println("Registered ContentProviders:");
5962 for (PackageParser.Provider p : mProviders.values()) {
5963 pw.println(" ["); pw.println(p.info.authority); pw.println("]: ");
5964 pw.println(p.toString());
5965 }
5966 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005967 }
5968
5969 static final class BasePermission {
5970 final static int TYPE_NORMAL = 0;
5971 final static int TYPE_BUILTIN = 1;
5972 final static int TYPE_DYNAMIC = 2;
5973
5974 final String name;
5975 final String sourcePackage;
5976 final int type;
5977 PackageParser.Permission perm;
5978 PermissionInfo pendingInfo;
5979 int uid;
5980 int[] gids;
5981
5982 BasePermission(String _name, String _sourcePackage, int _type) {
5983 name = _name;
5984 sourcePackage = _sourcePackage;
5985 type = _type;
5986 }
5987 }
5988
5989 static class PackageSignatures {
5990 private Signature[] mSignatures;
5991
5992 PackageSignatures(Signature[] sigs) {
5993 assignSignatures(sigs);
5994 }
5995
5996 PackageSignatures() {
5997 }
5998
5999 void writeXml(XmlSerializer serializer, String tagName,
6000 ArrayList<Signature> pastSignatures) throws IOException {
6001 if (mSignatures == null) {
6002 return;
6003 }
6004 serializer.startTag(null, tagName);
6005 serializer.attribute(null, "count",
6006 Integer.toString(mSignatures.length));
6007 for (int i=0; i<mSignatures.length; i++) {
6008 serializer.startTag(null, "cert");
6009 final Signature sig = mSignatures[i];
6010 final int sigHash = sig.hashCode();
6011 final int numPast = pastSignatures.size();
6012 int j;
6013 for (j=0; j<numPast; j++) {
6014 Signature pastSig = pastSignatures.get(j);
6015 if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
6016 serializer.attribute(null, "index", Integer.toString(j));
6017 break;
6018 }
6019 }
6020 if (j >= numPast) {
6021 pastSignatures.add(sig);
6022 serializer.attribute(null, "index", Integer.toString(numPast));
6023 serializer.attribute(null, "key", sig.toCharsString());
6024 }
6025 serializer.endTag(null, "cert");
6026 }
6027 serializer.endTag(null, tagName);
6028 }
6029
6030 void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
6031 throws IOException, XmlPullParserException {
6032 String countStr = parser.getAttributeValue(null, "count");
6033 if (countStr == null) {
6034 reportSettingsProblem(Log.WARN,
6035 "Error in package manager settings: <signatures> has"
6036 + " no count at " + parser.getPositionDescription());
6037 XmlUtils.skipCurrentTag(parser);
6038 }
6039 final int count = Integer.parseInt(countStr);
6040 mSignatures = new Signature[count];
6041 int pos = 0;
6042
6043 int outerDepth = parser.getDepth();
6044 int type;
6045 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6046 && (type != XmlPullParser.END_TAG
6047 || parser.getDepth() > outerDepth)) {
6048 if (type == XmlPullParser.END_TAG
6049 || type == XmlPullParser.TEXT) {
6050 continue;
6051 }
6052
6053 String tagName = parser.getName();
6054 if (tagName.equals("cert")) {
6055 if (pos < count) {
6056 String index = parser.getAttributeValue(null, "index");
6057 if (index != null) {
6058 try {
6059 int idx = Integer.parseInt(index);
6060 String key = parser.getAttributeValue(null, "key");
6061 if (key == null) {
6062 if (idx >= 0 && idx < pastSignatures.size()) {
6063 Signature sig = pastSignatures.get(idx);
6064 if (sig != null) {
6065 mSignatures[pos] = pastSignatures.get(idx);
6066 pos++;
6067 } else {
6068 reportSettingsProblem(Log.WARN,
6069 "Error in package manager settings: <cert> "
6070 + "index " + index + " is not defined at "
6071 + parser.getPositionDescription());
6072 }
6073 } else {
6074 reportSettingsProblem(Log.WARN,
6075 "Error in package manager settings: <cert> "
6076 + "index " + index + " is out of bounds at "
6077 + parser.getPositionDescription());
6078 }
6079 } else {
6080 while (pastSignatures.size() <= idx) {
6081 pastSignatures.add(null);
6082 }
6083 Signature sig = new Signature(key);
6084 pastSignatures.set(idx, sig);
6085 mSignatures[pos] = sig;
6086 pos++;
6087 }
6088 } catch (NumberFormatException e) {
6089 reportSettingsProblem(Log.WARN,
6090 "Error in package manager settings: <cert> "
6091 + "index " + index + " is not a number at "
6092 + parser.getPositionDescription());
6093 }
6094 } else {
6095 reportSettingsProblem(Log.WARN,
6096 "Error in package manager settings: <cert> has"
6097 + " no index at " + parser.getPositionDescription());
6098 }
6099 } else {
6100 reportSettingsProblem(Log.WARN,
6101 "Error in package manager settings: too "
6102 + "many <cert> tags, expected " + count
6103 + " at " + parser.getPositionDescription());
6104 }
6105 } else {
6106 reportSettingsProblem(Log.WARN,
6107 "Unknown element under <cert>: "
6108 + parser.getName());
6109 }
6110 XmlUtils.skipCurrentTag(parser);
6111 }
6112
6113 if (pos < count) {
6114 // Should never happen -- there is an error in the written
6115 // settings -- but if it does we don't want to generate
6116 // a bad array.
6117 Signature[] newSigs = new Signature[pos];
6118 System.arraycopy(mSignatures, 0, newSigs, 0, pos);
6119 mSignatures = newSigs;
6120 }
6121 }
6122
6123 /**
6124 * If any of the given 'sigs' is contained in the existing signatures,
6125 * then completely replace the current signatures with the ones in
6126 * 'sigs'. This is used for updating an existing package to a newly
6127 * installed version.
6128 */
6129 boolean updateSignatures(Signature[] sigs, boolean update) {
6130 if (mSignatures == null) {
6131 if (update) {
6132 assignSignatures(sigs);
6133 }
6134 return true;
6135 }
6136 if (sigs == null) {
6137 return false;
6138 }
6139
6140 for (int i=0; i<sigs.length; i++) {
6141 Signature sig = sigs[i];
6142 for (int j=0; j<mSignatures.length; j++) {
6143 if (mSignatures[j].equals(sig)) {
6144 if (update) {
6145 assignSignatures(sigs);
6146 }
6147 return true;
6148 }
6149 }
6150 }
6151 return false;
6152 }
6153
6154 /**
6155 * If any of the given 'sigs' is contained in the existing signatures,
6156 * then add in any new signatures found in 'sigs'. This is used for
6157 * including a new package into an existing shared user id.
6158 */
6159 boolean mergeSignatures(Signature[] sigs, boolean update) {
6160 if (mSignatures == null) {
6161 if (update) {
6162 assignSignatures(sigs);
6163 }
6164 return true;
6165 }
6166 if (sigs == null) {
6167 return false;
6168 }
6169
6170 Signature[] added = null;
6171 int addedCount = 0;
6172 boolean haveMatch = false;
6173 for (int i=0; i<sigs.length; i++) {
6174 Signature sig = sigs[i];
6175 boolean found = false;
6176 for (int j=0; j<mSignatures.length; j++) {
6177 if (mSignatures[j].equals(sig)) {
6178 found = true;
6179 haveMatch = true;
6180 break;
6181 }
6182 }
6183
6184 if (!found) {
6185 if (added == null) {
6186 added = new Signature[sigs.length];
6187 }
6188 added[i] = sig;
6189 addedCount++;
6190 }
6191 }
6192
6193 if (!haveMatch) {
6194 // Nothing matched -- reject the new signatures.
6195 return false;
6196 }
6197 if (added == null) {
6198 // Completely matched -- nothing else to do.
6199 return true;
6200 }
6201
6202 // Add additional signatures in.
6203 if (update) {
6204 Signature[] total = new Signature[addedCount+mSignatures.length];
6205 System.arraycopy(mSignatures, 0, total, 0, mSignatures.length);
6206 int j = mSignatures.length;
6207 for (int i=0; i<added.length; i++) {
6208 if (added[i] != null) {
6209 total[j] = added[i];
6210 j++;
6211 }
6212 }
6213 mSignatures = total;
6214 }
6215 return true;
6216 }
6217
6218 private void assignSignatures(Signature[] sigs) {
6219 if (sigs == null) {
6220 mSignatures = null;
6221 return;
6222 }
6223 mSignatures = new Signature[sigs.length];
6224 for (int i=0; i<sigs.length; i++) {
6225 mSignatures[i] = sigs[i];
6226 }
6227 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006229 @Override
6230 public String toString() {
6231 StringBuffer buf = new StringBuffer(128);
6232 buf.append("PackageSignatures{");
6233 buf.append(Integer.toHexString(System.identityHashCode(this)));
6234 buf.append(" [");
6235 if (mSignatures != null) {
6236 for (int i=0; i<mSignatures.length; i++) {
6237 if (i > 0) buf.append(", ");
6238 buf.append(Integer.toHexString(
6239 System.identityHashCode(mSignatures[i])));
6240 }
6241 }
6242 buf.append("]}");
6243 return buf.toString();
6244 }
6245 }
6246
6247 static class PreferredActivity extends IntentFilter {
6248 final int mMatch;
6249 final String[] mSetPackages;
6250 final String[] mSetClasses;
6251 final String[] mSetComponents;
6252 final ComponentName mActivity;
6253 final String mShortActivity;
6254 String mParseError;
6255
6256 PreferredActivity(IntentFilter filter, int match, ComponentName[] set,
6257 ComponentName activity) {
6258 super(filter);
6259 mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
6260 mActivity = activity;
6261 mShortActivity = activity.flattenToShortString();
6262 mParseError = null;
6263 if (set != null) {
6264 final int N = set.length;
6265 String[] myPackages = new String[N];
6266 String[] myClasses = new String[N];
6267 String[] myComponents = new String[N];
6268 for (int i=0; i<N; i++) {
6269 ComponentName cn = set[i];
6270 if (cn == null) {
6271 mSetPackages = null;
6272 mSetClasses = null;
6273 mSetComponents = null;
6274 return;
6275 }
6276 myPackages[i] = cn.getPackageName().intern();
6277 myClasses[i] = cn.getClassName().intern();
6278 myComponents[i] = cn.flattenToShortString().intern();
6279 }
6280 mSetPackages = myPackages;
6281 mSetClasses = myClasses;
6282 mSetComponents = myComponents;
6283 } else {
6284 mSetPackages = null;
6285 mSetClasses = null;
6286 mSetComponents = null;
6287 }
6288 }
6289
6290 PreferredActivity(XmlPullParser parser) throws XmlPullParserException,
6291 IOException {
6292 mShortActivity = parser.getAttributeValue(null, "name");
6293 mActivity = ComponentName.unflattenFromString(mShortActivity);
6294 if (mActivity == null) {
6295 mParseError = "Bad activity name " + mShortActivity;
6296 }
6297 String matchStr = parser.getAttributeValue(null, "match");
6298 mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
6299 String setCountStr = parser.getAttributeValue(null, "set");
6300 int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
6301
6302 String[] myPackages = setCount > 0 ? new String[setCount] : null;
6303 String[] myClasses = setCount > 0 ? new String[setCount] : null;
6304 String[] myComponents = setCount > 0 ? new String[setCount] : null;
6305
6306 int setPos = 0;
6307
6308 int outerDepth = parser.getDepth();
6309 int type;
6310 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
6311 && (type != XmlPullParser.END_TAG
6312 || parser.getDepth() > outerDepth)) {
6313 if (type == XmlPullParser.END_TAG
6314 || type == XmlPullParser.TEXT) {
6315 continue;
6316 }
6317
6318 String tagName = parser.getName();
6319 //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth="
6320 // + parser.getDepth() + " tag=" + tagName);
6321 if (tagName.equals("set")) {
6322 String name = parser.getAttributeValue(null, "name");
6323 if (name == null) {
6324 if (mParseError == null) {
6325 mParseError = "No name in set tag in preferred activity "
6326 + mShortActivity;
6327 }
6328 } else if (setPos >= setCount) {
6329 if (mParseError == null) {
6330 mParseError = "Too many set tags in preferred activity "
6331 + mShortActivity;
6332 }
6333 } else {
6334 ComponentName cn = ComponentName.unflattenFromString(name);
6335 if (cn == null) {
6336 if (mParseError == null) {
6337 mParseError = "Bad set name " + name + " in preferred activity "
6338 + mShortActivity;
6339 }
6340 } else {
6341 myPackages[setPos] = cn.getPackageName();
6342 myClasses[setPos] = cn.getClassName();
6343 myComponents[setPos] = name;
6344 setPos++;
6345 }
6346 }
6347 XmlUtils.skipCurrentTag(parser);
6348 } else if (tagName.equals("filter")) {
6349 //Log.i(TAG, "Starting to parse filter...");
6350 readFromXml(parser);
6351 //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth="
6352 // + parser.getDepth() + " tag=" + parser.getName());
6353 } else {
6354 reportSettingsProblem(Log.WARN,
6355 "Unknown element under <preferred-activities>: "
6356 + parser.getName());
6357 XmlUtils.skipCurrentTag(parser);
6358 }
6359 }
6360
6361 if (setPos != setCount) {
6362 if (mParseError == null) {
6363 mParseError = "Not enough set tags (expected " + setCount
6364 + " but found " + setPos + ") in " + mShortActivity;
6365 }
6366 }
6367
6368 mSetPackages = myPackages;
6369 mSetClasses = myClasses;
6370 mSetComponents = myComponents;
6371 }
6372
6373 public void writeToXml(XmlSerializer serializer) throws IOException {
6374 final int NS = mSetClasses != null ? mSetClasses.length : 0;
6375 serializer.attribute(null, "name", mShortActivity);
6376 serializer.attribute(null, "match", Integer.toHexString(mMatch));
6377 serializer.attribute(null, "set", Integer.toString(NS));
6378 for (int s=0; s<NS; s++) {
6379 serializer.startTag(null, "set");
6380 serializer.attribute(null, "name", mSetComponents[s]);
6381 serializer.endTag(null, "set");
6382 }
6383 serializer.startTag(null, "filter");
6384 super.writeToXml(serializer);
6385 serializer.endTag(null, "filter");
6386 }
6387
6388 boolean sameSet(List<ResolveInfo> query, int priority) {
6389 if (mSetPackages == null) return false;
6390 final int NQ = query.size();
6391 final int NS = mSetPackages.length;
6392 int numMatch = 0;
6393 for (int i=0; i<NQ; i++) {
6394 ResolveInfo ri = query.get(i);
6395 if (ri.priority != priority) continue;
6396 ActivityInfo ai = ri.activityInfo;
6397 boolean good = false;
6398 for (int j=0; j<NS; j++) {
6399 if (mSetPackages[j].equals(ai.packageName)
6400 && mSetClasses[j].equals(ai.name)) {
6401 numMatch++;
6402 good = true;
6403 break;
6404 }
6405 }
6406 if (!good) return false;
6407 }
6408 return numMatch == NS;
6409 }
6410 }
6411
6412 static class GrantedPermissions {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07006413 int pkgFlags;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006415 HashSet<String> grantedPermissions = new HashSet<String>();
6416 int[] gids;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006418 HashSet<String> loadedPermissions = new HashSet<String>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006420 GrantedPermissions(int pkgFlags) {
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08006421 this.pkgFlags = (pkgFlags & ApplicationInfo.FLAG_SYSTEM) |
6422 (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) |
6423 (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006424 }
6425 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006427 /**
6428 * Settings base class for pending and resolved classes.
6429 */
6430 static class PackageSettingBase extends GrantedPermissions {
6431 final String name;
Suchi Amalapurapuea5c0442009-07-13 10:36:15 -07006432 File codePath;
6433 String codePathString;
6434 File resourcePath;
6435 String resourcePathString;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006436 private long timeStamp;
6437 private String timeStampString = "0";
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006438 int versionCode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006439
6440 PackageSignatures signatures = new PackageSignatures();
6441
6442 boolean permissionsFixed;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006444 /* Explicitly disabled components */
6445 HashSet<String> disabledComponents = new HashSet<String>(0);
6446 /* Explicitly enabled components */
6447 HashSet<String> enabledComponents = new HashSet<String>(0);
6448 int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
6449 int installStatus = PKG_INSTALL_COMPLETE;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006450
Jacek Surazski65e13172009-04-28 15:26:38 +02006451 /* package name of the app that installed this package */
6452 String installerPackageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006453
6454 PackageSettingBase(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006455 int pVersionCode, int pkgFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006456 super(pkgFlags);
6457 this.name = name;
6458 this.codePath = codePath;
6459 this.codePathString = codePath.toString();
6460 this.resourcePath = resourcePath;
6461 this.resourcePathString = resourcePath.toString();
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006462 this.versionCode = pVersionCode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006463 }
6464
Jacek Surazski65e13172009-04-28 15:26:38 +02006465 public void setInstallerPackageName(String packageName) {
6466 installerPackageName = packageName;
6467 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006468
Jacek Surazski65e13172009-04-28 15:26:38 +02006469 String getInstallerPackageName() {
6470 return installerPackageName;
6471 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006473 public void setInstallStatus(int newStatus) {
6474 installStatus = newStatus;
6475 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006477 public int getInstallStatus() {
6478 return installStatus;
6479 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006481 public void setTimeStamp(long newStamp) {
6482 if (newStamp != timeStamp) {
6483 timeStamp = newStamp;
6484 timeStampString = Long.toString(newStamp);
6485 }
6486 }
6487
6488 public void setTimeStamp(long newStamp, String newStampStr) {
6489 timeStamp = newStamp;
6490 timeStampString = newStampStr;
6491 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006493 public long getTimeStamp() {
6494 return timeStamp;
6495 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006497 public String getTimeStampStr() {
6498 return timeStampString;
6499 }
6500
6501 public void copyFrom(PackageSettingBase base) {
6502 grantedPermissions = base.grantedPermissions;
6503 gids = base.gids;
6504 loadedPermissions = base.loadedPermissions;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006506 timeStamp = base.timeStamp;
6507 timeStampString = base.timeStampString;
6508 signatures = base.signatures;
6509 permissionsFixed = base.permissionsFixed;
6510 disabledComponents = base.disabledComponents;
6511 enabledComponents = base.enabledComponents;
6512 enabled = base.enabled;
6513 installStatus = base.installStatus;
6514 }
6515
6516 void enableComponentLP(String componentClassName) {
6517 disabledComponents.remove(componentClassName);
6518 enabledComponents.add(componentClassName);
6519 }
6520
6521 void disableComponentLP(String componentClassName) {
6522 enabledComponents.remove(componentClassName);
6523 disabledComponents.add(componentClassName);
6524 }
6525
6526 void restoreComponentLP(String componentClassName) {
6527 enabledComponents.remove(componentClassName);
6528 disabledComponents.remove(componentClassName);
6529 }
6530
6531 int currentEnabledStateLP(String componentName) {
6532 if (enabledComponents.contains(componentName)) {
6533 return COMPONENT_ENABLED_STATE_ENABLED;
6534 } else if (disabledComponents.contains(componentName)) {
6535 return COMPONENT_ENABLED_STATE_DISABLED;
6536 } else {
6537 return COMPONENT_ENABLED_STATE_DEFAULT;
6538 }
6539 }
6540 }
6541
6542 /**
6543 * Settings data for a particular package we know about.
6544 */
6545 static final class PackageSetting extends PackageSettingBase {
6546 int userId;
6547 PackageParser.Package pkg;
6548 SharedUserSetting sharedUser;
6549
6550 PackageSetting(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006551 int pVersionCode, int pkgFlags) {
6552 super(name, codePath, resourcePath, pVersionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006553 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006555 @Override
6556 public String toString() {
6557 return "PackageSetting{"
6558 + Integer.toHexString(System.identityHashCode(this))
6559 + " " + name + "/" + userId + "}";
6560 }
6561 }
6562
6563 /**
6564 * Settings data for a particular shared user ID we know about.
6565 */
6566 static final class SharedUserSetting extends GrantedPermissions {
6567 final String name;
6568 int userId;
6569 final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
6570 final PackageSignatures signatures = new PackageSignatures();
6571
6572 SharedUserSetting(String _name, int _pkgFlags) {
6573 super(_pkgFlags);
6574 name = _name;
6575 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006577 @Override
6578 public String toString() {
6579 return "SharedUserSetting{"
6580 + Integer.toHexString(System.identityHashCode(this))
6581 + " " + name + "/" + userId + "}";
6582 }
6583 }
6584
6585 /**
6586 * Holds information about dynamic settings.
6587 */
6588 private static final class Settings {
6589 private final File mSettingsFilename;
6590 private final File mBackupSettingsFilename;
6591 private final HashMap<String, PackageSetting> mPackages =
6592 new HashMap<String, PackageSetting>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006593 // List of replaced system applications
6594 final HashMap<String, PackageSetting> mDisabledSysPackages =
6595 new HashMap<String, PackageSetting>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006597 // The user's preferred activities associated with particular intent
6598 // filters.
6599 private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
6600 new IntentResolver<PreferredActivity, PreferredActivity>() {
6601 @Override
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006602 protected void dumpFilter(PrintWriter out, String prefix,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006603 PreferredActivity filter) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006604 out.print(prefix); out.print(
6605 Integer.toHexString(System.identityHashCode(filter)));
6606 out.print(' ');
6607 out.print(filter.mActivity.flattenToShortString());
6608 out.print(" match=0x");
6609 out.println( Integer.toHexString(filter.mMatch));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006610 if (filter.mSetComponents != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006611 out.print(prefix); out.println(" Selected from:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006612 for (int i=0; i<filter.mSetComponents.length; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006613 out.print(prefix); out.print(" ");
6614 out.println(filter.mSetComponents[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006615 }
6616 }
6617 }
6618 };
6619 private final HashMap<String, SharedUserSetting> mSharedUsers =
6620 new HashMap<String, SharedUserSetting>();
6621 private final ArrayList<Object> mUserIds = new ArrayList<Object>();
6622 private final SparseArray<Object> mOtherUserIds =
6623 new SparseArray<Object>();
6624
6625 // For reading/writing settings file.
6626 private final ArrayList<Signature> mPastSignatures =
6627 new ArrayList<Signature>();
6628
6629 // Mapping from permission names to info about them.
6630 final HashMap<String, BasePermission> mPermissions =
6631 new HashMap<String, BasePermission>();
6632
6633 // Mapping from permission tree names to info about them.
6634 final HashMap<String, BasePermission> mPermissionTrees =
6635 new HashMap<String, BasePermission>();
6636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006637 private final StringBuilder mReadMessages = new StringBuilder();
6638
6639 private static final class PendingPackage extends PackageSettingBase {
6640 final int sharedId;
6641
6642 PendingPackage(String name, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006643 int sharedId, int pVersionCode, int pkgFlags) {
6644 super(name, codePath, resourcePath, pVersionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006645 this.sharedId = sharedId;
6646 }
6647 }
6648 private final ArrayList<PendingPackage> mPendingPackages
6649 = new ArrayList<PendingPackage>();
6650
6651 Settings() {
6652 File dataDir = Environment.getDataDirectory();
6653 File systemDir = new File(dataDir, "system");
Oscar Montemayora8529f62009-11-18 10:14:20 -08006654 // TODO(oam): This secure dir creation needs to be moved somewhere else (later)
6655 File systemSecureDir = new File(dataDir, "secure/system");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006656 systemDir.mkdirs();
Oscar Montemayora8529f62009-11-18 10:14:20 -08006657 systemSecureDir.mkdirs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006658 FileUtils.setPermissions(systemDir.toString(),
6659 FileUtils.S_IRWXU|FileUtils.S_IRWXG
6660 |FileUtils.S_IROTH|FileUtils.S_IXOTH,
6661 -1, -1);
Oscar Montemayora8529f62009-11-18 10:14:20 -08006662 FileUtils.setPermissions(systemSecureDir.toString(),
6663 FileUtils.S_IRWXU|FileUtils.S_IRWXG
6664 |FileUtils.S_IROTH|FileUtils.S_IXOTH,
6665 -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006666 mSettingsFilename = new File(systemDir, "packages.xml");
6667 mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
6668 }
6669
6670 PackageSetting getPackageLP(PackageParser.Package pkg,
6671 SharedUserSetting sharedUser, File codePath, File resourcePath,
6672 int pkgFlags, boolean create, boolean add) {
6673 final String name = pkg.packageName;
6674 PackageSetting p = getPackageLP(name, sharedUser, codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006675 resourcePath, pkg.mVersionCode, pkgFlags, create, add);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006676 return p;
6677 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006678
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006679 PackageSetting peekPackageLP(String name) {
6680 return mPackages.get(name);
6681 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006682 PackageSetting p = mPackages.get(name);
6683 if (p != null && p.codePath.getPath().equals(codePath)) {
6684 return p;
6685 }
6686 return null;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006687 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006688 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006690 void setInstallStatus(String pkgName, int status) {
6691 PackageSetting p = mPackages.get(pkgName);
6692 if(p != null) {
6693 if(p.getInstallStatus() != status) {
6694 p.setInstallStatus(status);
6695 }
6696 }
6697 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006698
Jacek Surazski65e13172009-04-28 15:26:38 +02006699 void setInstallerPackageName(String pkgName,
6700 String installerPkgName) {
6701 PackageSetting p = mPackages.get(pkgName);
6702 if(p != null) {
6703 p.setInstallerPackageName(installerPkgName);
6704 }
6705 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006706
Jacek Surazski65e13172009-04-28 15:26:38 +02006707 String getInstallerPackageName(String pkgName) {
6708 PackageSetting p = mPackages.get(pkgName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006709 return (p == null) ? null : p.getInstallerPackageName();
Jacek Surazski65e13172009-04-28 15:26:38 +02006710 }
6711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006712 int getInstallStatus(String pkgName) {
6713 PackageSetting p = mPackages.get(pkgName);
6714 if(p != null) {
6715 return p.getInstallStatus();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006717 return -1;
6718 }
6719
6720 SharedUserSetting getSharedUserLP(String name,
6721 int pkgFlags, boolean create) {
6722 SharedUserSetting s = mSharedUsers.get(name);
6723 if (s == null) {
6724 if (!create) {
6725 return null;
6726 }
6727 s = new SharedUserSetting(name, pkgFlags);
6728 if (MULTIPLE_APPLICATION_UIDS) {
6729 s.userId = newUserIdLP(s);
6730 } else {
6731 s.userId = FIRST_APPLICATION_UID;
6732 }
6733 Log.i(TAG, "New shared user " + name + ": id=" + s.userId);
6734 // < 0 means we couldn't assign a userid; fall out and return
6735 // s, which is currently null
6736 if (s.userId >= 0) {
6737 mSharedUsers.put(name, s);
6738 }
6739 }
6740
6741 return s;
6742 }
6743
6744 int disableSystemPackageLP(String name) {
6745 PackageSetting p = mPackages.get(name);
6746 if(p == null) {
6747 Log.w(TAG, "Package:"+name+" is not an installed package");
6748 return -1;
6749 }
6750 PackageSetting dp = mDisabledSysPackages.get(name);
6751 // always make sure the system package code and resource paths dont change
6752 if(dp == null) {
6753 if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
6754 p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
6755 }
6756 mDisabledSysPackages.put(name, p);
6757 }
6758 return removePackageLP(name);
6759 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006761 PackageSetting enableSystemPackageLP(String name) {
6762 PackageSetting p = mDisabledSysPackages.get(name);
6763 if(p == null) {
6764 Log.w(TAG, "Package:"+name+" is not disabled");
6765 return null;
6766 }
6767 // Reset flag in ApplicationInfo object
6768 if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
6769 p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
6770 }
6771 PackageSetting ret = addPackageLP(name, p.codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006772 p.resourcePath, p.userId, p.versionCode, p.pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006773 mDisabledSysPackages.remove(name);
6774 return ret;
6775 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006776
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006777 PackageSetting addPackageLP(String name, File codePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006778 File resourcePath, int uid, int vc, int pkgFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006779 PackageSetting p = mPackages.get(name);
6780 if (p != null) {
6781 if (p.userId == uid) {
6782 return p;
6783 }
6784 reportSettingsProblem(Log.ERROR,
6785 "Adding duplicate package, keeping first: " + name);
6786 return null;
6787 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006788 p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006789 p.userId = uid;
6790 if (addUserIdLP(uid, p, name)) {
6791 mPackages.put(name, p);
6792 return p;
6793 }
6794 return null;
6795 }
6796
6797 SharedUserSetting addSharedUserLP(String name, int uid, int pkgFlags) {
6798 SharedUserSetting s = mSharedUsers.get(name);
6799 if (s != null) {
6800 if (s.userId == uid) {
6801 return s;
6802 }
6803 reportSettingsProblem(Log.ERROR,
6804 "Adding duplicate shared user, keeping first: " + name);
6805 return null;
6806 }
6807 s = new SharedUserSetting(name, pkgFlags);
6808 s.userId = uid;
6809 if (addUserIdLP(uid, s, name)) {
6810 mSharedUsers.put(name, s);
6811 return s;
6812 }
6813 return null;
6814 }
6815
6816 private PackageSetting getPackageLP(String name,
6817 SharedUserSetting sharedUser, File codePath, File resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006818 int vc, int pkgFlags, boolean create, boolean add) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006819 PackageSetting p = mPackages.get(name);
6820 if (p != null) {
6821 if (!p.codePath.equals(codePath)) {
6822 // Check to see if its a disabled system app
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006823 if((p != null) && ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
Suchi Amalapurapub24a9672009-07-01 14:04:43 -07006824 // This is an updated system app with versions in both system
6825 // and data partition. Just let the most recent version
6826 // take precedence.
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006827 Log.w(TAG, "Trying to update system app code path from " +
6828 p.codePathString + " to " + codePath.toString());
Suchi Amalapurapuea5c0442009-07-13 10:36:15 -07006829 } else {
Suchi Amalapurapub24a9672009-07-01 14:04:43 -07006830 // Let the app continue with previous uid if code path changes.
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07006831 reportSettingsProblem(Log.WARN,
6832 "Package " + name + " codePath changed from " + p.codePath
Dianne Hackborna33e3f72009-09-29 17:28:24 -07006833 + " to " + codePath + "; Retaining data and using new");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006834 }
Dianne Hackborna33e3f72009-09-29 17:28:24 -07006835 }
6836 if (p.sharedUser != sharedUser) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006837 reportSettingsProblem(Log.WARN,
6838 "Package " + name + " shared user changed from "
6839 + (p.sharedUser != null ? p.sharedUser.name : "<nothing>")
6840 + " to "
6841 + (sharedUser != null ? sharedUser.name : "<nothing>")
6842 + "; replacing with new");
6843 p = null;
Dianne Hackborna33e3f72009-09-29 17:28:24 -07006844 } else {
6845 if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
6846 // If what we are scanning is a system package, then
6847 // make it so, regardless of whether it was previously
6848 // installed only in the data partition.
6849 p.pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
6850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006851 }
6852 }
6853 if (p == null) {
6854 // Create a new PackageSettings entry. this can end up here because
6855 // of code path mismatch or user id mismatch of an updated system partition
6856 if (!create) {
6857 return null;
6858 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07006859 p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006860 p.setTimeStamp(codePath.lastModified());
Dianne Hackborn5d6d7732009-05-13 18:09:56 -07006861 p.sharedUser = sharedUser;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006862 if (sharedUser != null) {
6863 p.userId = sharedUser.userId;
6864 } else if (MULTIPLE_APPLICATION_UIDS) {
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006865 // Clone the setting here for disabled system packages
6866 PackageSetting dis = mDisabledSysPackages.get(name);
6867 if (dis != null) {
6868 // For disabled packages a new setting is created
6869 // from the existing user id. This still has to be
6870 // added to list of user id's
6871 // Copy signatures from previous setting
6872 if (dis.signatures.mSignatures != null) {
6873 p.signatures.mSignatures = dis.signatures.mSignatures.clone();
6874 }
6875 p.userId = dis.userId;
6876 // Clone permissions
6877 p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
6878 p.loadedPermissions = new HashSet<String>(dis.loadedPermissions);
6879 // Clone component info
6880 p.disabledComponents = new HashSet<String>(dis.disabledComponents);
6881 p.enabledComponents = new HashSet<String>(dis.enabledComponents);
6882 // Add new setting to list of user ids
6883 addUserIdLP(p.userId, p, name);
6884 } else {
6885 // Assign new user id
6886 p.userId = newUserIdLP(p);
6887 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006888 } else {
6889 p.userId = FIRST_APPLICATION_UID;
6890 }
6891 if (p.userId < 0) {
6892 reportSettingsProblem(Log.WARN,
6893 "Package " + name + " could not be assigned a valid uid");
6894 return null;
6895 }
6896 if (add) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006897 // Finish adding new package by adding it and updating shared
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006898 // user preferences
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006899 addPackageSettingLP(p, name, sharedUser);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006900 }
6901 }
6902 return p;
6903 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006904
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08006905 private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) {
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006906 p.pkg = pkg;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08006907 String codePath = pkg.applicationInfo.sourceDir;
6908 String resourcePath = pkg.applicationInfo.publicSourceDir;
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006909 // Update code path if needed
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08006910 if (!codePath.equalsIgnoreCase(p.codePathString)) {
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006911 Log.w(TAG, "Code path for pkg : " + p.pkg.packageName +
Dianne Hackborna33e3f72009-09-29 17:28:24 -07006912 " changing from " + p.codePathString + " to " + codePath);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08006913 p.codePath = new File(codePath);
6914 p.codePathString = codePath;
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006915 }
6916 //Update resource path if needed
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08006917 if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) {
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006918 Log.w(TAG, "Resource path for pkg : " + p.pkg.packageName +
Dianne Hackborna33e3f72009-09-29 17:28:24 -07006919 " changing from " + p.resourcePathString + " to " + resourcePath);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08006920 p.resourcePath = new File(resourcePath);
6921 p.resourcePathString = resourcePath;
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006922 }
6923 // Update version code if needed
6924 if (pkg.mVersionCode != p.versionCode) {
6925 p.versionCode = pkg.mVersionCode;
6926 }
6927 addPackageSettingLP(p, pkg.packageName, p.sharedUser);
6928 }
6929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006930 // Utility method that adds a PackageSetting to mPackages and
6931 // completes updating the shared user attributes
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07006932 private void addPackageSettingLP(PackageSetting p, String name,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006933 SharedUserSetting sharedUser) {
6934 mPackages.put(name, p);
6935 if (sharedUser != null) {
6936 if (p.sharedUser != null && p.sharedUser != sharedUser) {
6937 reportSettingsProblem(Log.ERROR,
6938 "Package " + p.name + " was user "
6939 + p.sharedUser + " but is now " + sharedUser
6940 + "; I am not changing its files so it will probably fail!");
6941 p.sharedUser.packages.remove(p);
6942 } else if (p.userId != sharedUser.userId) {
6943 reportSettingsProblem(Log.ERROR,
6944 "Package " + p.name + " was user id " + p.userId
6945 + " but is now user " + sharedUser
6946 + " with id " + sharedUser.userId
6947 + "; I am not changing its files so it will probably fail!");
6948 }
6949
6950 sharedUser.packages.add(p);
6951 p.sharedUser = sharedUser;
6952 p.userId = sharedUser.userId;
6953 }
6954 }
6955
Suchi Amalapurapu2ed287b2009-08-05 12:43:00 -07006956 /*
6957 * Update the shared user setting when a package using
6958 * specifying the shared user id is removed. The gids
6959 * associated with each permission of the deleted package
6960 * are removed from the shared user's gid list only if its
6961 * not in use by other permissions of packages in the
6962 * shared user setting.
6963 */
6964 private void updateSharedUserPermsLP(PackageSetting deletedPs, int[] globalGids) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006965 if ( (deletedPs == null) || (deletedPs.pkg == null)) {
6966 Log.i(TAG, "Trying to update info for null package. Just ignoring");
6967 return;
6968 }
6969 // No sharedUserId
6970 if (deletedPs.sharedUser == null) {
6971 return;
6972 }
6973 SharedUserSetting sus = deletedPs.sharedUser;
6974 // Update permissions
6975 for (String eachPerm: deletedPs.pkg.requestedPermissions) {
6976 boolean used = false;
6977 if (!sus.grantedPermissions.contains (eachPerm)) {
6978 continue;
6979 }
6980 for (PackageSetting pkg:sus.packages) {
Suchi Amalapurapud83006c2009-10-28 23:39:46 -07006981 if (pkg.pkg != null &&
6982 !pkg.pkg.packageName.equalsIgnoreCase(deletedPs.pkg.packageName) &&
6983 pkg.pkg.requestedPermissions.contains(eachPerm)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006984 used = true;
6985 break;
6986 }
6987 }
6988 if (!used) {
6989 // can safely delete this permission from list
6990 sus.grantedPermissions.remove(eachPerm);
6991 sus.loadedPermissions.remove(eachPerm);
6992 }
6993 }
6994 // Update gids
Suchi Amalapurapu2ed287b2009-08-05 12:43:00 -07006995 int newGids[] = globalGids;
6996 for (String eachPerm : sus.grantedPermissions) {
6997 BasePermission bp = mPermissions.get(eachPerm);
Suchi Amalapurapud83006c2009-10-28 23:39:46 -07006998 if (bp != null) {
6999 newGids = appendInts(newGids, bp.gids);
7000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007001 }
7002 sus.gids = newGids;
7003 }
Suchi Amalapurapu2ed287b2009-08-05 12:43:00 -07007004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007005 private int removePackageLP(String name) {
7006 PackageSetting p = mPackages.get(name);
7007 if (p != null) {
7008 mPackages.remove(name);
7009 if (p.sharedUser != null) {
7010 p.sharedUser.packages.remove(p);
7011 if (p.sharedUser.packages.size() == 0) {
7012 mSharedUsers.remove(p.sharedUser.name);
7013 removeUserIdLP(p.sharedUser.userId);
7014 return p.sharedUser.userId;
7015 }
7016 } else {
7017 removeUserIdLP(p.userId);
7018 return p.userId;
7019 }
7020 }
7021 return -1;
7022 }
7023
7024 private boolean addUserIdLP(int uid, Object obj, Object name) {
7025 if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) {
7026 return false;
7027 }
7028
7029 if (uid >= FIRST_APPLICATION_UID) {
7030 int N = mUserIds.size();
7031 final int index = uid - FIRST_APPLICATION_UID;
7032 while (index >= N) {
7033 mUserIds.add(null);
7034 N++;
7035 }
7036 if (mUserIds.get(index) != null) {
7037 reportSettingsProblem(Log.ERROR,
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07007038 "Adding duplicate user id: " + uid
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007039 + " name=" + name);
7040 return false;
7041 }
7042 mUserIds.set(index, obj);
7043 } else {
7044 if (mOtherUserIds.get(uid) != null) {
7045 reportSettingsProblem(Log.ERROR,
7046 "Adding duplicate shared id: " + uid
7047 + " name=" + name);
7048 return false;
7049 }
7050 mOtherUserIds.put(uid, obj);
7051 }
7052 return true;
7053 }
7054
7055 public Object getUserIdLP(int uid) {
7056 if (uid >= FIRST_APPLICATION_UID) {
7057 int N = mUserIds.size();
7058 final int index = uid - FIRST_APPLICATION_UID;
7059 return index < N ? mUserIds.get(index) : null;
7060 } else {
7061 return mOtherUserIds.get(uid);
7062 }
7063 }
7064
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08007065 private Set<String> findPackagesWithFlag(int flag) {
7066 Set<String> ret = new HashSet<String>();
7067 for (PackageSetting ps : mPackages.values()) {
7068 // Has to match atleast all the flag bits set on flag
7069 if ((ps.pkgFlags & flag) == flag) {
7070 ret.add(ps.name);
7071 }
7072 }
7073 return ret;
7074 }
7075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007076 private void removeUserIdLP(int uid) {
7077 if (uid >= FIRST_APPLICATION_UID) {
7078 int N = mUserIds.size();
7079 final int index = uid - FIRST_APPLICATION_UID;
7080 if (index < N) mUserIds.set(index, null);
7081 } else {
7082 mOtherUserIds.remove(uid);
7083 }
7084 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007086 void writeLP() {
7087 //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
7088
7089 // Keep the old settings around until we know the new ones have
7090 // been successfully written.
7091 if (mSettingsFilename.exists()) {
Suchi Amalapurapu14e833f2009-10-20 11:27:32 -07007092 // Presence of backup settings file indicates that we failed
7093 // to persist settings earlier. So preserve the older
7094 // backup for future reference since the current settings
7095 // might have been corrupted.
7096 if (!mBackupSettingsFilename.exists()) {
7097 if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
7098 Log.w(TAG, "Unable to backup package manager settings, current changes will be lost at reboot");
7099 return;
7100 }
7101 } else {
7102 Log.w(TAG, "Preserving older settings backup");
Suchi Amalapurapu3d7e8552009-09-17 15:38:20 -07007103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007104 }
7105
7106 mPastSignatures.clear();
7107
7108 try {
7109 FileOutputStream str = new FileOutputStream(mSettingsFilename);
7110
7111 //XmlSerializer serializer = XmlUtils.serializerInstance();
7112 XmlSerializer serializer = new FastXmlSerializer();
7113 serializer.setOutput(str, "utf-8");
7114 serializer.startDocument(null, true);
7115 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
7116
7117 serializer.startTag(null, "packages");
7118
7119 serializer.startTag(null, "permission-trees");
7120 for (BasePermission bp : mPermissionTrees.values()) {
7121 writePermission(serializer, bp);
7122 }
7123 serializer.endTag(null, "permission-trees");
7124
7125 serializer.startTag(null, "permissions");
7126 for (BasePermission bp : mPermissions.values()) {
7127 writePermission(serializer, bp);
7128 }
7129 serializer.endTag(null, "permissions");
7130
7131 for (PackageSetting pkg : mPackages.values()) {
7132 writePackage(serializer, pkg);
7133 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007135 for (PackageSetting pkg : mDisabledSysPackages.values()) {
7136 writeDisabledSysPackage(serializer, pkg);
7137 }
7138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007139 serializer.startTag(null, "preferred-activities");
7140 for (PreferredActivity pa : mPreferredActivities.filterSet()) {
7141 serializer.startTag(null, "item");
7142 pa.writeToXml(serializer);
7143 serializer.endTag(null, "item");
7144 }
7145 serializer.endTag(null, "preferred-activities");
7146
7147 for (SharedUserSetting usr : mSharedUsers.values()) {
7148 serializer.startTag(null, "shared-user");
7149 serializer.attribute(null, "name", usr.name);
7150 serializer.attribute(null, "userId",
7151 Integer.toString(usr.userId));
7152 usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
7153 serializer.startTag(null, "perms");
7154 for (String name : usr.grantedPermissions) {
7155 serializer.startTag(null, "item");
7156 serializer.attribute(null, "name", name);
7157 serializer.endTag(null, "item");
7158 }
7159 serializer.endTag(null, "perms");
7160 serializer.endTag(null, "shared-user");
7161 }
7162
7163 serializer.endTag(null, "packages");
7164
7165 serializer.endDocument();
7166
7167 str.flush();
7168 str.close();
7169
7170 // New settings successfully written, old ones are no longer
7171 // needed.
7172 mBackupSettingsFilename.delete();
7173 FileUtils.setPermissions(mSettingsFilename.toString(),
7174 FileUtils.S_IRUSR|FileUtils.S_IWUSR
7175 |FileUtils.S_IRGRP|FileUtils.S_IWGRP
7176 |FileUtils.S_IROTH,
7177 -1, -1);
Suchi Amalapurapu8550f252009-09-29 15:20:32 -07007178 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007179
7180 } catch(XmlPullParserException e) {
7181 Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007182 } catch(java.io.IOException e) {
7183 Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007184 }
Suchi Amalapurapu8550f252009-09-29 15:20:32 -07007185 // Clean up partially written file
7186 if (mSettingsFilename.exists()) {
7187 if (!mSettingsFilename.delete()) {
7188 Log.i(TAG, "Failed to clean up mangled file: " + mSettingsFilename);
7189 }
7190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007191 //Debug.stopMethodTracing();
7192 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007193
7194 void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007195 throws java.io.IOException {
7196 serializer.startTag(null, "updated-package");
7197 serializer.attribute(null, "name", pkg.name);
7198 serializer.attribute(null, "codePath", pkg.codePathString);
7199 serializer.attribute(null, "ts", pkg.getTimeStampStr());
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007200 serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007201 if (!pkg.resourcePathString.equals(pkg.codePathString)) {
7202 serializer.attribute(null, "resourcePath", pkg.resourcePathString);
7203 }
7204 if (pkg.sharedUser == null) {
7205 serializer.attribute(null, "userId",
7206 Integer.toString(pkg.userId));
7207 } else {
7208 serializer.attribute(null, "sharedUserId",
7209 Integer.toString(pkg.userId));
7210 }
7211 serializer.startTag(null, "perms");
7212 if (pkg.sharedUser == null) {
7213 // If this is a shared user, the permissions will
7214 // be written there. We still need to write an
7215 // empty permissions list so permissionsFixed will
7216 // be set.
7217 for (final String name : pkg.grantedPermissions) {
7218 BasePermission bp = mPermissions.get(name);
7219 if ((bp != null) && (bp.perm != null) && (bp.perm.info != null)) {
7220 // We only need to write signature or system permissions but this wont
7221 // match the semantics of grantedPermissions. So write all permissions.
7222 serializer.startTag(null, "item");
7223 serializer.attribute(null, "name", name);
7224 serializer.endTag(null, "item");
7225 }
7226 }
7227 }
7228 serializer.endTag(null, "perms");
7229 serializer.endTag(null, "updated-package");
7230 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007231
7232 void writePackage(XmlSerializer serializer, final PackageSetting pkg)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007233 throws java.io.IOException {
7234 serializer.startTag(null, "package");
7235 serializer.attribute(null, "name", pkg.name);
7236 serializer.attribute(null, "codePath", pkg.codePathString);
7237 if (!pkg.resourcePathString.equals(pkg.codePathString)) {
7238 serializer.attribute(null, "resourcePath", pkg.resourcePathString);
7239 }
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08007240 serializer.attribute(null, "flags",
7241 Integer.toString(pkg.pkgFlags));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007242 serializer.attribute(null, "ts", pkg.getTimeStampStr());
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007243 serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007244 if (pkg.sharedUser == null) {
7245 serializer.attribute(null, "userId",
7246 Integer.toString(pkg.userId));
7247 } else {
7248 serializer.attribute(null, "sharedUserId",
7249 Integer.toString(pkg.userId));
7250 }
7251 if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
7252 serializer.attribute(null, "enabled",
7253 pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
7254 ? "true" : "false");
7255 }
7256 if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
7257 serializer.attribute(null, "installStatus", "false");
7258 }
Jacek Surazski65e13172009-04-28 15:26:38 +02007259 if (pkg.installerPackageName != null) {
7260 serializer.attribute(null, "installer", pkg.installerPackageName);
7261 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007262 pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
7263 if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
7264 serializer.startTag(null, "perms");
7265 if (pkg.sharedUser == null) {
7266 // If this is a shared user, the permissions will
7267 // be written there. We still need to write an
7268 // empty permissions list so permissionsFixed will
7269 // be set.
7270 for (final String name : pkg.grantedPermissions) {
7271 serializer.startTag(null, "item");
7272 serializer.attribute(null, "name", name);
7273 serializer.endTag(null, "item");
7274 }
7275 }
7276 serializer.endTag(null, "perms");
7277 }
7278 if (pkg.disabledComponents.size() > 0) {
7279 serializer.startTag(null, "disabled-components");
7280 for (final String name : pkg.disabledComponents) {
7281 serializer.startTag(null, "item");
7282 serializer.attribute(null, "name", name);
7283 serializer.endTag(null, "item");
7284 }
7285 serializer.endTag(null, "disabled-components");
7286 }
7287 if (pkg.enabledComponents.size() > 0) {
7288 serializer.startTag(null, "enabled-components");
7289 for (final String name : pkg.enabledComponents) {
7290 serializer.startTag(null, "item");
7291 serializer.attribute(null, "name", name);
7292 serializer.endTag(null, "item");
7293 }
7294 serializer.endTag(null, "enabled-components");
7295 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007297 serializer.endTag(null, "package");
7298 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007300 void writePermission(XmlSerializer serializer, BasePermission bp)
7301 throws XmlPullParserException, java.io.IOException {
7302 if (bp.type != BasePermission.TYPE_BUILTIN
7303 && bp.sourcePackage != null) {
7304 serializer.startTag(null, "item");
7305 serializer.attribute(null, "name", bp.name);
7306 serializer.attribute(null, "package", bp.sourcePackage);
7307 if (DEBUG_SETTINGS) Log.v(TAG,
7308 "Writing perm: name=" + bp.name + " type=" + bp.type);
7309 if (bp.type == BasePermission.TYPE_DYNAMIC) {
7310 PermissionInfo pi = bp.perm != null ? bp.perm.info
7311 : bp.pendingInfo;
7312 if (pi != null) {
7313 serializer.attribute(null, "type", "dynamic");
7314 if (pi.icon != 0) {
7315 serializer.attribute(null, "icon",
7316 Integer.toString(pi.icon));
7317 }
7318 if (pi.nonLocalizedLabel != null) {
7319 serializer.attribute(null, "label",
7320 pi.nonLocalizedLabel.toString());
7321 }
7322 if (pi.protectionLevel !=
7323 PermissionInfo.PROTECTION_NORMAL) {
7324 serializer.attribute(null, "protection",
7325 Integer.toString(pi.protectionLevel));
7326 }
7327 }
7328 }
7329 serializer.endTag(null, "item");
7330 }
7331 }
7332
7333 String getReadMessagesLP() {
7334 return mReadMessages.toString();
7335 }
7336
Oscar Montemayora8529f62009-11-18 10:14:20 -08007337 ArrayList<PackageSetting> getListOfIncompleteInstallPackages() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007338 HashSet<String> kList = new HashSet<String>(mPackages.keySet());
7339 Iterator<String> its = kList.iterator();
Oscar Montemayora8529f62009-11-18 10:14:20 -08007340 ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007341 while(its.hasNext()) {
7342 String key = its.next();
7343 PackageSetting ps = mPackages.get(key);
7344 if(ps.getInstallStatus() == PKG_INSTALL_INCOMPLETE) {
Oscar Montemayora8529f62009-11-18 10:14:20 -08007345 ret.add(ps);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007346 }
7347 }
7348 return ret;
7349 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007351 boolean readLP() {
7352 FileInputStream str = null;
7353 if (mBackupSettingsFilename.exists()) {
7354 try {
7355 str = new FileInputStream(mBackupSettingsFilename);
7356 mReadMessages.append("Reading from backup settings file\n");
7357 Log.i(TAG, "Reading from backup settings file!");
Suchi Amalapurapu14e833f2009-10-20 11:27:32 -07007358 if (mSettingsFilename.exists()) {
7359 // If both the backup and settings file exist, we
7360 // ignore the settings since it might have been
7361 // corrupted.
7362 Log.w(TAG, "Cleaning up settings file " + mSettingsFilename);
7363 mSettingsFilename.delete();
7364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007365 } catch (java.io.IOException e) {
7366 // We'll try for the normal settings file.
7367 }
7368 }
7369
7370 mPastSignatures.clear();
7371
7372 try {
7373 if (str == null) {
7374 if (!mSettingsFilename.exists()) {
7375 mReadMessages.append("No settings file found\n");
7376 Log.i(TAG, "No current settings file!");
7377 return false;
7378 }
7379 str = new FileInputStream(mSettingsFilename);
7380 }
7381 XmlPullParser parser = Xml.newPullParser();
7382 parser.setInput(str, null);
7383
7384 int type;
7385 while ((type=parser.next()) != XmlPullParser.START_TAG
7386 && type != XmlPullParser.END_DOCUMENT) {
7387 ;
7388 }
7389
7390 if (type != XmlPullParser.START_TAG) {
7391 mReadMessages.append("No start tag found in settings file\n");
7392 Log.e(TAG, "No start tag found in package manager settings");
7393 return false;
7394 }
7395
7396 int outerDepth = parser.getDepth();
7397 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7398 && (type != XmlPullParser.END_TAG
7399 || parser.getDepth() > outerDepth)) {
7400 if (type == XmlPullParser.END_TAG
7401 || type == XmlPullParser.TEXT) {
7402 continue;
7403 }
7404
7405 String tagName = parser.getName();
7406 if (tagName.equals("package")) {
7407 readPackageLP(parser);
7408 } else if (tagName.equals("permissions")) {
7409 readPermissionsLP(mPermissions, parser);
7410 } else if (tagName.equals("permission-trees")) {
7411 readPermissionsLP(mPermissionTrees, parser);
7412 } else if (tagName.equals("shared-user")) {
7413 readSharedUserLP(parser);
7414 } else if (tagName.equals("preferred-packages")) {
Dianne Hackborna7ca0e52009-12-01 14:31:55 -08007415 // no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007416 } else if (tagName.equals("preferred-activities")) {
7417 readPreferredActivitiesLP(parser);
7418 } else if(tagName.equals("updated-package")) {
7419 readDisabledSysPackageLP(parser);
7420 } else {
7421 Log.w(TAG, "Unknown element under <packages>: "
7422 + parser.getName());
7423 XmlUtils.skipCurrentTag(parser);
7424 }
7425 }
7426
7427 str.close();
7428
7429 } catch(XmlPullParserException e) {
7430 mReadMessages.append("Error reading: " + e.toString());
7431 Log.e(TAG, "Error reading package manager settings", e);
7432
7433 } catch(java.io.IOException e) {
7434 mReadMessages.append("Error reading: " + e.toString());
7435 Log.e(TAG, "Error reading package manager settings", e);
7436
7437 }
7438
7439 int N = mPendingPackages.size();
7440 for (int i=0; i<N; i++) {
7441 final PendingPackage pp = mPendingPackages.get(i);
7442 Object idObj = getUserIdLP(pp.sharedId);
7443 if (idObj != null && idObj instanceof SharedUserSetting) {
7444 PackageSetting p = getPackageLP(pp.name,
7445 (SharedUserSetting)idObj, pp.codePath, pp.resourcePath,
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007446 pp.versionCode, pp.pkgFlags, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007447 if (p == null) {
7448 Log.w(TAG, "Unable to create application package for "
7449 + pp.name);
7450 continue;
7451 }
7452 p.copyFrom(pp);
7453 } else if (idObj != null) {
7454 String msg = "Bad package setting: package " + pp.name
7455 + " has shared uid " + pp.sharedId
7456 + " that is not a shared uid\n";
7457 mReadMessages.append(msg);
7458 Log.e(TAG, msg);
7459 } else {
7460 String msg = "Bad package setting: package " + pp.name
7461 + " has shared uid " + pp.sharedId
7462 + " that is not defined\n";
7463 mReadMessages.append(msg);
7464 Log.e(TAG, msg);
7465 }
7466 }
7467 mPendingPackages.clear();
7468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007469 mReadMessages.append("Read completed successfully: "
7470 + mPackages.size() + " packages, "
7471 + mSharedUsers.size() + " shared uids\n");
7472
7473 return true;
7474 }
7475
7476 private int readInt(XmlPullParser parser, String ns, String name,
7477 int defValue) {
7478 String v = parser.getAttributeValue(ns, name);
7479 try {
7480 if (v == null) {
7481 return defValue;
7482 }
7483 return Integer.parseInt(v);
7484 } catch (NumberFormatException e) {
7485 reportSettingsProblem(Log.WARN,
7486 "Error in package manager settings: attribute " +
7487 name + " has bad integer value " + v + " at "
7488 + parser.getPositionDescription());
7489 }
7490 return defValue;
7491 }
7492
7493 private void readPermissionsLP(HashMap<String, BasePermission> out,
7494 XmlPullParser parser)
7495 throws IOException, XmlPullParserException {
7496 int outerDepth = parser.getDepth();
7497 int type;
7498 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7499 && (type != XmlPullParser.END_TAG
7500 || parser.getDepth() > outerDepth)) {
7501 if (type == XmlPullParser.END_TAG
7502 || type == XmlPullParser.TEXT) {
7503 continue;
7504 }
7505
7506 String tagName = parser.getName();
7507 if (tagName.equals("item")) {
7508 String name = parser.getAttributeValue(null, "name");
7509 String sourcePackage = parser.getAttributeValue(null, "package");
7510 String ptype = parser.getAttributeValue(null, "type");
7511 if (name != null && sourcePackage != null) {
7512 boolean dynamic = "dynamic".equals(ptype);
7513 BasePermission bp = new BasePermission(name, sourcePackage,
7514 dynamic
7515 ? BasePermission.TYPE_DYNAMIC
7516 : BasePermission.TYPE_NORMAL);
7517 if (dynamic) {
7518 PermissionInfo pi = new PermissionInfo();
7519 pi.packageName = sourcePackage.intern();
7520 pi.name = name.intern();
7521 pi.icon = readInt(parser, null, "icon", 0);
7522 pi.nonLocalizedLabel = parser.getAttributeValue(
7523 null, "label");
7524 pi.protectionLevel = readInt(parser, null, "protection",
7525 PermissionInfo.PROTECTION_NORMAL);
7526 bp.pendingInfo = pi;
7527 }
7528 out.put(bp.name, bp);
7529 } else {
7530 reportSettingsProblem(Log.WARN,
7531 "Error in package manager settings: permissions has"
7532 + " no name at " + parser.getPositionDescription());
7533 }
7534 } else {
7535 reportSettingsProblem(Log.WARN,
7536 "Unknown element reading permissions: "
7537 + parser.getName() + " at "
7538 + parser.getPositionDescription());
7539 }
7540 XmlUtils.skipCurrentTag(parser);
7541 }
7542 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007544 private void readDisabledSysPackageLP(XmlPullParser parser)
7545 throws XmlPullParserException, IOException {
7546 String name = parser.getAttributeValue(null, "name");
7547 String codePathStr = parser.getAttributeValue(null, "codePath");
7548 String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
7549 if(resourcePathStr == null) {
7550 resourcePathStr = codePathStr;
7551 }
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007552 String version = parser.getAttributeValue(null, "version");
7553 int versionCode = 0;
7554 if (version != null) {
7555 try {
7556 versionCode = Integer.parseInt(version);
7557 } catch (NumberFormatException e) {
7558 }
7559 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007561 int pkgFlags = 0;
7562 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007563 PackageSetting ps = new PackageSetting(name,
7564 new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007565 new File(resourcePathStr), versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007566 String timeStampStr = parser.getAttributeValue(null, "ts");
7567 if (timeStampStr != null) {
7568 try {
7569 long timeStamp = Long.parseLong(timeStampStr);
7570 ps.setTimeStamp(timeStamp, timeStampStr);
7571 } catch (NumberFormatException e) {
7572 }
7573 }
7574 String idStr = parser.getAttributeValue(null, "userId");
7575 ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
7576 if(ps.userId <= 0) {
7577 String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
7578 ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
7579 }
7580 int outerDepth = parser.getDepth();
7581 int type;
7582 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7583 && (type != XmlPullParser.END_TAG
7584 || parser.getDepth() > outerDepth)) {
7585 if (type == XmlPullParser.END_TAG
7586 || type == XmlPullParser.TEXT) {
7587 continue;
7588 }
7589
7590 String tagName = parser.getName();
7591 if (tagName.equals("perms")) {
7592 readGrantedPermissionsLP(parser,
7593 ps.grantedPermissions);
7594 } else {
7595 reportSettingsProblem(Log.WARN,
7596 "Unknown element under <updated-package>: "
7597 + parser.getName());
7598 XmlUtils.skipCurrentTag(parser);
7599 }
7600 }
7601 mDisabledSysPackages.put(name, ps);
7602 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007604 private void readPackageLP(XmlPullParser parser)
7605 throws XmlPullParserException, IOException {
7606 String name = null;
7607 String idStr = null;
7608 String sharedIdStr = null;
7609 String codePathStr = null;
7610 String resourcePathStr = null;
7611 String systemStr = null;
Jacek Surazski65e13172009-04-28 15:26:38 +02007612 String installerPackageName = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007613 int pkgFlags = 0;
7614 String timeStampStr;
7615 long timeStamp = 0;
7616 PackageSettingBase packageSetting = null;
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007617 String version = null;
7618 int versionCode = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007619 try {
7620 name = parser.getAttributeValue(null, "name");
7621 idStr = parser.getAttributeValue(null, "userId");
7622 sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
7623 codePathStr = parser.getAttributeValue(null, "codePath");
7624 resourcePathStr = parser.getAttributeValue(null, "resourcePath");
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007625 version = parser.getAttributeValue(null, "version");
7626 if (version != null) {
7627 try {
7628 versionCode = Integer.parseInt(version);
7629 } catch (NumberFormatException e) {
7630 }
7631 }
Jacek Surazski65e13172009-04-28 15:26:38 +02007632 installerPackageName = parser.getAttributeValue(null, "installer");
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08007633
7634 systemStr = parser.getAttributeValue(null, "flags");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007635 if (systemStr != null) {
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08007636 try {
7637 pkgFlags = Integer.parseInt(systemStr);
7638 } catch (NumberFormatException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007639 }
7640 } else {
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08007641 // For backward compatibility
7642 systemStr = parser.getAttributeValue(null, "system");
7643 if (systemStr != null) {
7644 pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM : 0;
7645 } else {
7646 // Old settings that don't specify system... just treat
7647 // them as system, good enough.
7648 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
7649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007650 }
7651 timeStampStr = parser.getAttributeValue(null, "ts");
7652 if (timeStampStr != null) {
7653 try {
7654 timeStamp = Long.parseLong(timeStampStr);
7655 } catch (NumberFormatException e) {
7656 }
7657 }
7658 if (DEBUG_SETTINGS) Log.v(TAG, "Reading package: " + name
7659 + " userId=" + idStr + " sharedUserId=" + sharedIdStr);
7660 int userId = idStr != null ? Integer.parseInt(idStr) : 0;
7661 if (resourcePathStr == null) {
7662 resourcePathStr = codePathStr;
7663 }
7664 if (name == null) {
7665 reportSettingsProblem(Log.WARN,
7666 "Error in package manager settings: <package> has no name at "
7667 + parser.getPositionDescription());
7668 } else if (codePathStr == null) {
7669 reportSettingsProblem(Log.WARN,
7670 "Error in package manager settings: <package> has no codePath at "
7671 + parser.getPositionDescription());
7672 } else if (userId > 0) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007673 packageSetting = addPackageLP(name.intern(), new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007674 new File(resourcePathStr), userId, versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007675 if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
7676 + ": userId=" + userId + " pkg=" + packageSetting);
7677 if (packageSetting == null) {
7678 reportSettingsProblem(Log.ERROR,
7679 "Failure adding uid " + userId
7680 + " while parsing settings at "
7681 + parser.getPositionDescription());
7682 } else {
7683 packageSetting.setTimeStamp(timeStamp, timeStampStr);
7684 }
7685 } else if (sharedIdStr != null) {
7686 userId = sharedIdStr != null
7687 ? Integer.parseInt(sharedIdStr) : 0;
7688 if (userId > 0) {
7689 packageSetting = new PendingPackage(name.intern(), new File(codePathStr),
Suchi Amalapurapuc2af31f2009-05-08 14:44:41 -07007690 new File(resourcePathStr), userId, versionCode, pkgFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007691 packageSetting.setTimeStamp(timeStamp, timeStampStr);
7692 mPendingPackages.add((PendingPackage) packageSetting);
7693 if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
7694 + ": sharedUserId=" + userId + " pkg="
7695 + packageSetting);
7696 } else {
7697 reportSettingsProblem(Log.WARN,
7698 "Error in package manager settings: package "
7699 + name + " has bad sharedId " + sharedIdStr
7700 + " at " + parser.getPositionDescription());
7701 }
7702 } else {
7703 reportSettingsProblem(Log.WARN,
7704 "Error in package manager settings: package "
7705 + name + " has bad userId " + idStr + " at "
7706 + parser.getPositionDescription());
7707 }
7708 } catch (NumberFormatException e) {
7709 reportSettingsProblem(Log.WARN,
7710 "Error in package manager settings: package "
7711 + name + " has bad userId " + idStr + " at "
7712 + parser.getPositionDescription());
7713 }
7714 if (packageSetting != null) {
Jacek Surazski65e13172009-04-28 15:26:38 +02007715 packageSetting.installerPackageName = installerPackageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007716 final String enabledStr = parser.getAttributeValue(null, "enabled");
7717 if (enabledStr != null) {
7718 if (enabledStr.equalsIgnoreCase("true")) {
7719 packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
7720 } else if (enabledStr.equalsIgnoreCase("false")) {
7721 packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
7722 } else if (enabledStr.equalsIgnoreCase("default")) {
7723 packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
7724 } else {
7725 reportSettingsProblem(Log.WARN,
7726 "Error in package manager settings: package "
7727 + name + " has bad enabled value: " + idStr
7728 + " at " + parser.getPositionDescription());
7729 }
7730 } else {
7731 packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
7732 }
7733 final String installStatusStr = parser.getAttributeValue(null, "installStatus");
7734 if (installStatusStr != null) {
7735 if (installStatusStr.equalsIgnoreCase("false")) {
7736 packageSetting.installStatus = PKG_INSTALL_INCOMPLETE;
7737 } else {
7738 packageSetting.installStatus = PKG_INSTALL_COMPLETE;
7739 }
7740 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007742 int outerDepth = parser.getDepth();
7743 int type;
7744 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7745 && (type != XmlPullParser.END_TAG
7746 || parser.getDepth() > outerDepth)) {
7747 if (type == XmlPullParser.END_TAG
7748 || type == XmlPullParser.TEXT) {
7749 continue;
7750 }
7751
7752 String tagName = parser.getName();
7753 if (tagName.equals("disabled-components")) {
7754 readDisabledComponentsLP(packageSetting, parser);
7755 } else if (tagName.equals("enabled-components")) {
7756 readEnabledComponentsLP(packageSetting, parser);
7757 } else if (tagName.equals("sigs")) {
7758 packageSetting.signatures.readXml(parser, mPastSignatures);
7759 } else if (tagName.equals("perms")) {
7760 readGrantedPermissionsLP(parser,
7761 packageSetting.loadedPermissions);
7762 packageSetting.permissionsFixed = true;
7763 } else {
7764 reportSettingsProblem(Log.WARN,
7765 "Unknown element under <package>: "
7766 + parser.getName());
7767 XmlUtils.skipCurrentTag(parser);
7768 }
7769 }
7770 } else {
7771 XmlUtils.skipCurrentTag(parser);
7772 }
7773 }
7774
7775 private void readDisabledComponentsLP(PackageSettingBase packageSetting,
7776 XmlPullParser parser)
7777 throws IOException, XmlPullParserException {
7778 int outerDepth = parser.getDepth();
7779 int type;
7780 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7781 && (type != XmlPullParser.END_TAG
7782 || parser.getDepth() > outerDepth)) {
7783 if (type == XmlPullParser.END_TAG
7784 || type == XmlPullParser.TEXT) {
7785 continue;
7786 }
7787
7788 String tagName = parser.getName();
7789 if (tagName.equals("item")) {
7790 String name = parser.getAttributeValue(null, "name");
7791 if (name != null) {
7792 packageSetting.disabledComponents.add(name.intern());
7793 } else {
7794 reportSettingsProblem(Log.WARN,
7795 "Error in package manager settings: <disabled-components> has"
7796 + " no name at " + parser.getPositionDescription());
7797 }
7798 } else {
7799 reportSettingsProblem(Log.WARN,
7800 "Unknown element under <disabled-components>: "
7801 + parser.getName());
7802 }
7803 XmlUtils.skipCurrentTag(parser);
7804 }
7805 }
7806
7807 private void readEnabledComponentsLP(PackageSettingBase packageSetting,
7808 XmlPullParser parser)
7809 throws IOException, XmlPullParserException {
7810 int outerDepth = parser.getDepth();
7811 int type;
7812 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7813 && (type != XmlPullParser.END_TAG
7814 || parser.getDepth() > outerDepth)) {
7815 if (type == XmlPullParser.END_TAG
7816 || type == XmlPullParser.TEXT) {
7817 continue;
7818 }
7819
7820 String tagName = parser.getName();
7821 if (tagName.equals("item")) {
7822 String name = parser.getAttributeValue(null, "name");
7823 if (name != null) {
7824 packageSetting.enabledComponents.add(name.intern());
7825 } else {
7826 reportSettingsProblem(Log.WARN,
7827 "Error in package manager settings: <enabled-components> has"
7828 + " no name at " + parser.getPositionDescription());
7829 }
7830 } else {
7831 reportSettingsProblem(Log.WARN,
7832 "Unknown element under <enabled-components>: "
7833 + parser.getName());
7834 }
7835 XmlUtils.skipCurrentTag(parser);
7836 }
7837 }
7838
7839 private void readSharedUserLP(XmlPullParser parser)
7840 throws XmlPullParserException, IOException {
7841 String name = null;
7842 String idStr = null;
7843 int pkgFlags = 0;
7844 SharedUserSetting su = null;
7845 try {
7846 name = parser.getAttributeValue(null, "name");
7847 idStr = parser.getAttributeValue(null, "userId");
7848 int userId = idStr != null ? Integer.parseInt(idStr) : 0;
7849 if ("true".equals(parser.getAttributeValue(null, "system"))) {
7850 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
7851 }
7852 if (name == null) {
7853 reportSettingsProblem(Log.WARN,
7854 "Error in package manager settings: <shared-user> has no name at "
7855 + parser.getPositionDescription());
7856 } else if (userId == 0) {
7857 reportSettingsProblem(Log.WARN,
7858 "Error in package manager settings: shared-user "
7859 + name + " has bad userId " + idStr + " at "
7860 + parser.getPositionDescription());
7861 } else {
7862 if ((su=addSharedUserLP(name.intern(), userId, pkgFlags)) == null) {
7863 reportSettingsProblem(Log.ERROR,
7864 "Occurred while parsing settings at "
7865 + parser.getPositionDescription());
7866 }
7867 }
7868 } catch (NumberFormatException e) {
7869 reportSettingsProblem(Log.WARN,
7870 "Error in package manager settings: package "
7871 + name + " has bad userId " + idStr + " at "
7872 + parser.getPositionDescription());
7873 };
7874
7875 if (su != null) {
7876 int outerDepth = parser.getDepth();
7877 int type;
7878 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7879 && (type != XmlPullParser.END_TAG
7880 || parser.getDepth() > outerDepth)) {
7881 if (type == XmlPullParser.END_TAG
7882 || type == XmlPullParser.TEXT) {
7883 continue;
7884 }
7885
7886 String tagName = parser.getName();
7887 if (tagName.equals("sigs")) {
7888 su.signatures.readXml(parser, mPastSignatures);
7889 } else if (tagName.equals("perms")) {
7890 readGrantedPermissionsLP(parser, su.loadedPermissions);
7891 } else {
7892 reportSettingsProblem(Log.WARN,
7893 "Unknown element under <shared-user>: "
7894 + parser.getName());
7895 XmlUtils.skipCurrentTag(parser);
7896 }
7897 }
7898
7899 } else {
7900 XmlUtils.skipCurrentTag(parser);
7901 }
7902 }
7903
7904 private void readGrantedPermissionsLP(XmlPullParser parser,
7905 HashSet<String> outPerms) throws IOException, XmlPullParserException {
7906 int outerDepth = parser.getDepth();
7907 int type;
7908 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7909 && (type != XmlPullParser.END_TAG
7910 || parser.getDepth() > outerDepth)) {
7911 if (type == XmlPullParser.END_TAG
7912 || type == XmlPullParser.TEXT) {
7913 continue;
7914 }
7915
7916 String tagName = parser.getName();
7917 if (tagName.equals("item")) {
7918 String name = parser.getAttributeValue(null, "name");
7919 if (name != null) {
7920 outPerms.add(name.intern());
7921 } else {
7922 reportSettingsProblem(Log.WARN,
7923 "Error in package manager settings: <perms> has"
7924 + " no name at " + parser.getPositionDescription());
7925 }
7926 } else {
7927 reportSettingsProblem(Log.WARN,
7928 "Unknown element under <perms>: "
7929 + parser.getName());
7930 }
7931 XmlUtils.skipCurrentTag(parser);
7932 }
7933 }
7934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007935 private void readPreferredActivitiesLP(XmlPullParser parser)
7936 throws XmlPullParserException, IOException {
7937 int outerDepth = parser.getDepth();
7938 int type;
7939 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
7940 && (type != XmlPullParser.END_TAG
7941 || parser.getDepth() > outerDepth)) {
7942 if (type == XmlPullParser.END_TAG
7943 || type == XmlPullParser.TEXT) {
7944 continue;
7945 }
7946
7947 String tagName = parser.getName();
7948 if (tagName.equals("item")) {
7949 PreferredActivity pa = new PreferredActivity(parser);
7950 if (pa.mParseError == null) {
7951 mPreferredActivities.addFilter(pa);
7952 } else {
7953 reportSettingsProblem(Log.WARN,
7954 "Error in package manager settings: <preferred-activity> "
7955 + pa.mParseError + " at "
7956 + parser.getPositionDescription());
7957 }
7958 } else {
7959 reportSettingsProblem(Log.WARN,
7960 "Unknown element under <preferred-activities>: "
7961 + parser.getName());
7962 XmlUtils.skipCurrentTag(parser);
7963 }
7964 }
7965 }
7966
7967 // Returns -1 if we could not find an available UserId to assign
7968 private int newUserIdLP(Object obj) {
7969 // Let's be stupidly inefficient for now...
7970 final int N = mUserIds.size();
7971 for (int i=0; i<N; i++) {
7972 if (mUserIds.get(i) == null) {
7973 mUserIds.set(i, obj);
7974 return FIRST_APPLICATION_UID + i;
7975 }
7976 }
7977
7978 // None left?
7979 if (N >= MAX_APPLICATION_UIDS) {
7980 return -1;
7981 }
7982
7983 mUserIds.add(obj);
7984 return FIRST_APPLICATION_UID + N;
7985 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08007986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007987 public PackageSetting getDisabledSystemPkg(String name) {
7988 synchronized(mPackages) {
7989 PackageSetting ps = mDisabledSysPackages.get(name);
7990 return ps;
7991 }
7992 }
7993
7994 boolean isEnabledLP(ComponentInfo componentInfo, int flags) {
7995 final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
7996 if (Config.LOGV) {
7997 Log.v(TAG, "isEnabledLock - packageName = " + componentInfo.packageName
7998 + " componentName = " + componentInfo.name);
7999 Log.v(TAG, "enabledComponents: "
8000 + Arrays.toString(packageSettings.enabledComponents.toArray()));
8001 Log.v(TAG, "disabledComponents: "
8002 + Arrays.toString(packageSettings.disabledComponents.toArray()));
8003 }
8004 return ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0)
8005 || ((componentInfo.enabled
8006 && ((packageSettings.enabled == COMPONENT_ENABLED_STATE_ENABLED)
8007 || (componentInfo.applicationInfo.enabled
8008 && packageSettings.enabled != COMPONENT_ENABLED_STATE_DISABLED))
8009 && !packageSettings.disabledComponents.contains(componentInfo.name))
8010 || packageSettings.enabledComponents.contains(componentInfo.name));
8011 }
8012 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008013
8014 // ------- apps on sdcard specific code -------
8015 static final boolean DEBUG_SD_INSTALL = false;
Oscar Montemayord02546b2010-01-14 16:38:40 -08008016 final private String mSdEncryptKey = "AppsOnSD";
Oscar Montemayor462f0372010-01-14 16:38:40 -08008017 final private String mSdEncryptAlg = "AES";
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08008018 private boolean mMediaMounted = false;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08008019 private static final int MAX_CONTAINERS = 250;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008020
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08008021
8022 static MountService getMountService() {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008023 return (MountService) ServiceManager.getService("mount");
8024 }
8025
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08008026 private String getEncryptKey() {
8027 try {
8028 String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
8029 if (sdEncKey == null) {
8030 sdEncKey = SystemKeyStore.getInstance().
8031 generateNewKeyHexString(128, mSdEncryptAlg, mSdEncryptKey);
8032 if (sdEncKey == null) {
8033 Log.e(TAG, "Failed to create encryption keys");
8034 return null;
8035 }
8036 }
8037 return sdEncKey;
8038 } catch (NoSuchAlgorithmException nsae) {
8039 Log.e(TAG, "Failed to create encryption keys with exception: " + nsae);
8040 return null;
8041 }
8042 }
8043
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008044 private String createSdDir(File tmpPackageFile, String pkgName) {
8045 // Create mount point via MountService
8046 MountService mountService = getMountService();
8047 long len = tmpPackageFile.length();
8048 int mbLen = (int) (len/(1024*1024));
8049 if ((len - (mbLen * 1024 * 1024)) > 0) {
8050 mbLen++;
8051 }
8052 if (DEBUG_SD_INSTALL) Log.i(TAG, "mbLen="+mbLen);
8053 String cachePath = null;
Oscar Montemayord02546b2010-01-14 16:38:40 -08008054 String sdEncKey;
8055 try {
8056 sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
8057 if (sdEncKey == null) {
8058 sdEncKey = SystemKeyStore.getInstance().
8059 generateNewKeyHexString(128, mSdEncryptAlg, mSdEncryptKey);
8060 if (sdEncKey == null) {
8061 Log.e(TAG, "Failed to create encryption keys for package: " + pkgName + ".");
8062 return null;
8063 }
8064 }
8065 } catch (NoSuchAlgorithmException nsae) {
8066 Log.e(TAG, "Failed to create encryption keys with exception: " + nsae);
8067 return null;
8068 }
San Mehatbe16cb12010-01-29 05:35:35 -08008069
8070 int rc = mountService.createSecureContainer(
8071 pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID);
8072 if (rc != MountServiceResultCode.OperationSucceeded) {
8073 Log.e(TAG, String.format("Failed to create container (%d)", rc));
8074
8075 rc = mountService.destroySecureContainer(pkgName);
8076 if (rc != MountServiceResultCode.OperationSucceeded) {
8077 Log.e(TAG, String.format("Failed to cleanup container (%d)", rc));
8078 return null;
8079 }
8080 rc = mountService.createSecureContainer(
8081 pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID);
8082 if (rc != MountServiceResultCode.OperationSucceeded) {
8083 Log.e(TAG, String.format("Failed to create container (2nd try) (%d)", rc));
8084 return null;
8085 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008086 }
San Mehatbe16cb12010-01-29 05:35:35 -08008087
8088 cachePath = mountService.getSecureContainerPath(pkgName);
8089 if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install " + pkgName + ", cachePath =" + cachePath);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008090 return cachePath;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008091 }
8092
8093 private String mountSdDir(String pkgName, int ownerUid) {
Oscar Montemayord02546b2010-01-14 16:38:40 -08008094 String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
8095 if (sdEncKey == null) {
8096 Log.e(TAG, "Failed to retrieve encryption keys to mount package code: " + pkgName + ".");
8097 return null;
8098 }
San Mehatbe16cb12010-01-29 05:35:35 -08008099
8100 int rc = getMountService().mountSecureContainer(pkgName, sdEncKey, ownerUid);
8101
8102 if (rc != MountServiceResultCode.OperationSucceeded) {
8103 Log.i(TAG, "Failed to mount container for pkg : " + pkgName + " rc : " + rc);
8104 return null;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008105 }
San Mehatbe16cb12010-01-29 05:35:35 -08008106
8107 return getMountService().getSecureContainerPath(pkgName);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008108 }
8109
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08008110 private boolean unMountSdDir(String pkgName) {
8111 // STOPSHIP unmount directory
San Mehatbe16cb12010-01-29 05:35:35 -08008112 int rc = getMountService().unmountSecureContainer(pkgName);
8113 if (rc != MountServiceResultCode.OperationSucceeded) {
8114 Log.e(TAG, "Failed to unmount : " + pkgName + " with rc " + rc);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008115 return false;
8116 }
San Mehatbe16cb12010-01-29 05:35:35 -08008117 return true;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008118 }
8119
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08008120 private boolean renameSdDir(String oldId, String newId) {
8121 try {
8122 getMountService().renameSecureContainer(oldId, newId);
8123 return true;
8124 } catch (IllegalStateException e) {
8125 Log.i(TAG, "Failed ot rename " + oldId + " to " + newId +
8126 " with exception : " + e);
8127 }
8128 return false;
8129 }
8130
8131 private String getSdDir(String pkgName) {
8132 return getMountService().getSecureContainerPath(pkgName);
8133 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008134
San Mehatbe16cb12010-01-29 05:35:35 -08008135 private boolean finalizeSdDir(String pkgName) {
8136 int rc = getMountService().finalizeSecureContainer(pkgName);
8137 if (rc != MountServiceResultCode.OperationSucceeded) {
8138 Log.i(TAG, "Failed to finalize container for pkg : " + pkgName);
8139 return false;
8140 }
8141 return true;
8142 }
8143
8144 private boolean destroySdDir(String pkgName) {
8145 int rc = getMountService().destroySecureContainer(pkgName);
8146 if (rc != MountServiceResultCode.OperationSucceeded) {
8147 Log.i(TAG, "Failed to destroy container for pkg : " + pkgName);
8148 return false;
8149 }
8150 return true;
8151 }
8152
8153 static String[] getSecureContainerList() {
8154 String[] list = getMountService().getSecureContainerList();
8155 return list.length == 0 ? null : list;
8156 }
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08008157
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08008158 static boolean isContainerMounted(String cid) {
8159 // STOPSHIP
8160 // New api from MountService
8161 try {
8162 return (getMountService().getSecureContainerPath(cid) != null);
8163 } catch (IllegalStateException e) {
8164 }
8165 return false;
8166 }
8167
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08008168 static String getTempContainerId() {
8169 String prefix = "smdl1tmp";
8170 int tmpIdx = 1;
8171 String list[] = getSecureContainerList();
8172 if (list != null) {
8173 int idx = 0;
8174 int idList[] = new int[MAX_CONTAINERS];
8175 boolean neverFound = true;
8176 for (String name : list) {
8177 // Ignore null entries
8178 if (name == null) {
8179 continue;
8180 }
8181 int sidx = name.indexOf(prefix);
8182 if (sidx == -1) {
8183 // Not a temp file. just ignore
8184 continue;
8185 }
8186 String subStr = name.substring(sidx + prefix.length());
8187 idList[idx] = -1;
8188 if (subStr != null) {
8189 try {
8190 int cid = Integer.parseInt(subStr);
8191 idList[idx++] = cid;
8192 neverFound = false;
8193 } catch (NumberFormatException e) {
8194 }
8195 }
8196 }
8197 if (!neverFound) {
8198 // Sort idList
8199 Arrays.sort(idList);
8200 for (int j = 1; j <= idList.length; j++) {
8201 if (idList[j-1] != j) {
8202 tmpIdx = j;
8203 break;
8204 }
8205 }
8206 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008207 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -08008208 return prefix + tmpIdx;
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008209 }
8210
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08008211 public void updateExternalMediaStatus(final boolean mediaStatus) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08008212 final boolean DEBUG = true;
8213 if (DEBUG) Log.i(TAG, "updateExterMediaStatus::");
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08008214 if (mediaStatus == mMediaMounted) {
8215 return;
8216 }
8217 mMediaMounted = mediaStatus;
8218 // Queue up an async operation since the package installation may take a little while.
8219 mHandler.post(new Runnable() {
8220 public void run() {
8221 mHandler.removeCallbacks(this);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08008222 updateExternalMediaStatusInner(mediaStatus);
8223 }
8224 });
8225 }
8226
8227 void updateExternalMediaStatusInner(boolean mediaStatus) {
8228 final String list[] = getSecureContainerList();
8229 if (list == null || list.length == 0) {
8230 return;
8231 }
8232 HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
8233 int uidList[] = new int[list.length];
8234 int num = 0;
8235 for (int i = 0; i < uidList.length; i++) {
8236 uidList[i] = Process.LAST_APPLICATION_UID;
8237 }
8238 synchronized (mPackages) {
8239 Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD);
8240 for (String cid : list) {
8241 SdInstallArgs args = new SdInstallArgs(cid);
8242 String removeEntry = null;
8243 for (String app : appList) {
8244 if (args.matchContainer(app)) {
8245 removeEntry = app;
8246 break;
8247 }
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08008248 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08008249 if (removeEntry == null) {
8250 // No matching app on device. Skip entry or may be cleanup?
8251 // Ignore default package
8252 continue;
8253 }
8254 appList.remove(removeEntry);
8255 PackageSetting ps = mSettings.mPackages.get(removeEntry);
8256 processCids.put(args, ps.codePathString);
8257 int uid = ps.userId;
8258 if (uid != -1) {
8259 int idx = Arrays.binarySearch(uidList, uid);
8260 if (idx < 0) {
8261 uidList[-idx] = uid;
8262 num++;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -08008263 }
8264 }
8265 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08008266 }
8267 int uidArr[] = uidList;
8268 if ((num > 0) && (num < uidList.length)) {
8269 uidArr = new int[num];
8270 for (int i = 0; i < num; i++) {
8271 uidArr[i] = uidList[i];
8272 }
8273 }
8274 if (mediaStatus) {
8275 loadMediaPackages(processCids, uidArr);
8276 } else {
8277 unloadMediaPackages(processCids, uidArr);
8278 }
8279 }
8280
8281 private void sendResourcesChangedBroadcast(boolean mediaStatus,
8282 ArrayList<String> pkgList, int uidArr[]) {
8283 int size = pkgList.size();
8284 if (size > 0) {
8285 // Send broadcasts here
8286 Bundle extras = new Bundle();
8287 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
8288 pkgList.toArray(new String[size]));
8289 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
8290 String action = mediaStatus ? Intent.ACTION_MEDIA_RESOURCES_AVAILABLE
8291 : Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE;
8292 sendPackageBroadcast(action, null, extras);
8293 }
8294 }
8295
8296 void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
8297 ArrayList<String> pkgList = new ArrayList<String>();
8298 Set<SdInstallArgs> keys = processCids.keySet();
8299 for (SdInstallArgs args : keys) {
8300 String cid = args.cid;
8301 String codePath = processCids.get(args);
8302 if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
8303 Log.i(TAG, "Failed to install package: " + codePath + " from sdcard");
8304 continue;
8305 }
8306 // Parse package
8307 int parseFlags = PackageParser.PARSE_CHATTY |
8308 PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
8309 PackageParser pp = new PackageParser(codePath);
8310 pp.setSeparateProcesses(mSeparateProcesses);
8311 final PackageParser.Package pkg = pp.parsePackage(new File(codePath),
8312 codePath, mMetrics, parseFlags);
8313 if (pkg == null) {
8314 Log.w(TAG, "Failed to install package : " + cid + " from sd card");
8315 continue;
8316 }
8317 setApplicationInfoPaths(pkg, codePath, codePath);
8318 int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
8319 synchronized (mInstallLock) {
8320 // Scan the package
8321 if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
8322 synchronized (mPackages) {
8323 // Grant permissions
8324 grantPermissionsLP(pkg, false);
8325 // Persist settings
8326 mSettings.writeLP();
8327 retCode = PackageManager.INSTALL_SUCCEEDED;
8328 pkgList.add(pkg.packageName);
8329 }
8330 } else {
8331 Log.i(TAG, "Failed to install package: " + pkg.packageName + " from sdcard");
8332 }
8333 }
8334 args.doPostInstall(retCode);
8335 pkgList.add(pkg.packageName);
8336 }
8337 // Send broadcasts first
8338 sendResourcesChangedBroadcast(true, pkgList, uidArr);
8339 Runtime.getRuntime().gc();
8340 // If something failed do we clean up here or next install?
8341 }
8342
8343 void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
8344 ArrayList<String> pkgList = new ArrayList<String>();
8345 Set<SdInstallArgs> keys = processCids.keySet();
8346 for (SdInstallArgs args : keys) {
8347 String cid = args.cid;
8348 String pkgName = args.getPackageName();
8349 // STOPSHIP Send broadcast to apps to remove references
8350 // STOPSHIP Unmount package
8351 // Delete package internally
8352 PackageRemovedInfo outInfo = new PackageRemovedInfo();
8353 synchronized (mInstallLock) {
8354 boolean res = deletePackageLI(pkgName, false,
8355 PackageManager.DONT_DELETE_DATA, outInfo);
8356 if (res) {
8357 pkgList.add(pkgName);
8358 } else {
8359 Log.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
8360 }
8361 }
8362 }
8363 // Send broadcasts
8364 sendResourcesChangedBroadcast(false, pkgList, uidArr);
8365 Runtime.getRuntime().gc();
8366 // Do clean up. Just unmount
8367 for (SdInstallArgs args : keys) {
8368 synchronized (mInstallLock) {
8369 args.doPostDeleteLI(false);
8370 }
8371 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -08008372 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008373}