diff options
Diffstat (limited to 'services/java')
17 files changed, 773 insertions, 466 deletions
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java index b56b13b..407983d 100644 --- a/services/java/com/android/server/AccessibilityManagerService.java +++ b/services/java/com/android/server/AccessibilityManagerService.java @@ -176,8 +176,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub context.registerReceiver(broadcastReceiver, packageFilter); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(broadcastReceiver, sdFilter); // boot completed diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index c28cf44..44cc0bb 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -782,7 +782,7 @@ class AlarmManagerService extends IAlarmManager.Stub { mContext.registerReceiver(this, filter); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(this, sdFilter); } @@ -791,7 +791,7 @@ class AlarmManagerService extends IAlarmManager.Stub { synchronized (mLock) { String action = intent.getAction(); String pkgList[] = null; - if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else { Uri data = intent.getData(); diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 684f117..f336d1f 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -147,8 +147,8 @@ class AppWidgetService extends IAppWidgetService.Stub mContext.registerReceiver(mBroadcastReceiver, filter); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); } @@ -1077,10 +1077,10 @@ class AppWidgetService extends IAppWidgetService.Stub } else { boolean added = false; String pkgList[] = null; - if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); added = true; - } if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + } if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); added = false; } else { diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 2f845e1..27055ed 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -76,6 +76,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.Set; class BackupManagerService extends IBackupManager.Stub { private static final String TAG = "BackupManagerService"; @@ -226,7 +227,9 @@ class BackupManagerService extends IBackupManager.Stub { private File mEverStored; HashSet<String> mEverStoredApps = new HashSet<String>(); + static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1; // increment when the schema changes File mTokenFile; + Set<String> mAncestralPackages = null; long mAncestralToken = 0; long mCurrentToken = 0; @@ -500,8 +503,20 @@ class BackupManagerService extends IBackupManager.Stub { mTokenFile = new File(mBaseStateDir, "ancestral"); try { RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r"); - mAncestralToken = tf.readLong(); - mCurrentToken = tf.readLong(); + int version = tf.readInt(); + if (version == CURRENT_ANCESTRAL_RECORD_VERSION) { + mAncestralToken = tf.readLong(); + mCurrentToken = tf.readLong(); + + int numPackages = tf.readInt(); + if (numPackages >= 0) { + mAncestralPackages = new HashSet<String>(); + for (int i = 0; i < numPackages; i++) { + String pkgName = tf.readUTF(); + mAncestralPackages.add(pkgName); + } + } + } } catch (IOException e) { Log.w(TAG, "Unable to read token file", e); } @@ -565,8 +580,8 @@ class BackupManagerService extends IBackupManager.Stub { mContext.registerReceiver(mBroadcastReceiver, filter); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); } @@ -724,10 +739,10 @@ class BackupManagerService extends IBackupManager.Stub { } added = Intent.ACTION_PACKAGE_ADDED.equals(action); replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); - } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) { + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { added = true; pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); - } else if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { added = false; pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } @@ -972,12 +987,31 @@ class BackupManagerService extends IBackupManager.Stub { } } - // Record the current and ancestral backup tokens persistently + // Persistently record the current and ancestral backup tokens as well + // as the set of packages with data [supposedly] available in the + // ancestral dataset. void writeRestoreTokens() { try { RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd"); + + // First, the version number of this record, for futureproofing + af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION); + + // Write the ancestral and current tokens af.writeLong(mAncestralToken); af.writeLong(mCurrentToken); + + // Now write the set of ancestral packages + if (mAncestralPackages == null) { + af.writeInt(-1); + } else { + af.writeInt(mAncestralPackages.size()); + if (DEBUG) Log.v(TAG, "Ancestral packages: " + mAncestralPackages.size()); + for (String pkgName : mAncestralPackages) { + af.writeUTF(pkgName); + if (DEBUG) Log.v(TAG, " " + pkgName); + } + } af.close(); } catch (IOException e) { Log.w(TAG, "Unable to write token file:", e); @@ -1502,6 +1536,7 @@ class BackupManagerService extends IBackupManager.Stub { * the user is waiting, after all. */ + PackageManagerBackupAgent pmAgent = null; int error = -1; // assume error // build the set of apps to restore @@ -1562,7 +1597,7 @@ class BackupManagerService extends IBackupManager.Stub { } // Pull the Package Manager metadata from the restore set first - PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent( + pmAgent = new PackageManagerBackupAgent( mPackageManager, agentPackages); processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind())); @@ -1705,8 +1740,10 @@ class BackupManagerService extends IBackupManager.Stub { } // If this was a restoreAll operation, record that this was our - // ancestral dataset - if (mTargetPackage == null) { + // ancestral dataset, as well as the set of apps that are possibly + // restoreable from the dataset + if (mTargetPackage == null && pmAgent != null) { + mAncestralPackages = pmAgent.getRestoredPackages(); mAncestralToken = mToken; writeRestoreTokens(); } @@ -2436,6 +2473,12 @@ class BackupManagerService extends IBackupManager.Stub { } } + pw.println("Ancestral packages: " + + (mAncestralPackages == null ? "none" : mAncestralPackages.size())); + for (String pkg : mAncestralPackages) { + pw.println(" " + pkg); + } + pw.println("Ever backed up: " + mEverStoredApps.size()); for (String pkg : mEverStoredApps) { pw.println(" " + pkg); diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index e4ee4ae..1625d9f 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -320,14 +320,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } tag = parser.getName(); if ("admin".equals(tag)) { - DeviceAdminInfo dai = findAdmin( - ComponentName.unflattenFromString( - parser.getAttributeValue(null, "name"))); - if (dai != null) { - ActiveAdmin ap = new ActiveAdmin(dai); - ap.readFromXml(parser); - mAdminMap.put(ap.info.getComponent(), ap); - mAdminList.add(ap); + String name = parser.getAttributeValue(null, "name"); + try { + DeviceAdminInfo dai = findAdmin( + ComponentName.unflattenFromString(name)); + if (dai != null) { + ActiveAdmin ap = new ActiveAdmin(dai); + ap.readFromXml(parser); + mAdminMap.put(ap.info.getComponent(), ap); + mAdminList.add(ap); + } + } catch (RuntimeException e) { + Log.w(TAG, "Failed loading admin " + name, e); } } else if ("failed-password-attempts".equals(tag)) { mFailedPasswordAttempts = Integer.parseInt( diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index dc942a2..5e96a2f 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -344,8 +344,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (pkg != null) { pkgList = new String[] { pkg }; } - } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) || - Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) || + Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } if (pkgList == null || pkgList.length == 0) { @@ -448,8 +448,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mContext.registerReceiver(mBroadcastReceiver, packageFilt); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); IntentFilter screenOnOffFilt = new IntentFilter(); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 3a42b37..fff6c54 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -29,16 +29,18 @@ import java.util.Set; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.ContentQueryMap; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.ServiceConnection; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.database.Cursor; import android.location.Address; import android.location.GeocoderParams; -import android.location.IGeocodeProvider; import android.location.IGpsStatusListener; import android.location.IGpsStatusProvider; import android.location.ILocationListener; @@ -64,10 +66,11 @@ import android.provider.Settings; import android.util.Log; import android.util.PrintWriterPrinter; +import com.android.internal.location.GeocoderProxy; import com.android.internal.location.GpsLocationProvider; +import com.android.internal.location.GpsNetInitiatedHandler; import com.android.internal.location.LocationProviderProxy; import com.android.internal.location.MockProvider; -import com.android.internal.location.GpsNetInitiatedHandler; /** * The service class that manages LocationProviders and issues location @@ -105,7 +108,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private static boolean sProvidersLoaded = false; private final Context mContext; - private IGeocodeProvider mGeocodeProvider; + private GeocoderProxy mGeocodeProvider; private IGpsStatusProvider mGpsStatusProvider; private INetInitiatedListener mNetInitiatedListener; private LocationWorkerHandler mLocationHandler; @@ -415,7 +418,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private void removeProvider(LocationProviderProxy provider) { mProviders.remove(provider); - provider.unlinkProvider(); mProvidersByName.remove(provider.getName()); } @@ -446,11 +448,28 @@ public class LocationManagerService extends ILocationManager.Stub implements Run GpsLocationProvider provider = new GpsLocationProvider(mContext, this); mGpsStatusProvider = provider.getGpsStatusProvider(); mNetInitiatedListener = provider.getNetInitiatedListener(); - LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider); + LocationProviderProxy proxy = + new LocationProviderProxy(mContext, LocationManager.GPS_PROVIDER, provider); addProvider(proxy); mGpsLocationProvider = proxy; } + // initialize external network location and geocoder services + Resources resources = mContext.getResources(); + String serviceName = resources.getString( + com.android.internal.R.string.config_networkLocationProvider); + if (serviceName != null) { + mNetworkLocationProvider = + new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER, + serviceName, mLocationHandler); + addProvider(mNetworkLocationProvider); + } + + serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider); + if (serviceName != null) { + mGeocodeProvider = new GeocoderProxy(mContext, serviceName); + } + updateProvidersLocked(); } @@ -484,7 +503,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); mContext.registerReceiver(mBroadcastReceiver, intentFilter); - IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); // listen for settings changes @@ -507,45 +526,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run Looper.loop(); } - public void installLocationProvider(String name, ILocationProvider provider) { - if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission"); - } - - synchronized (mLock) { - // check to see if we are reinstalling a dead provider - LocationProviderProxy oldProvider = mProvidersByName.get(name); - if (oldProvider != null) { - if (oldProvider.isDead()) { - Log.d(TAG, "replacing dead provider"); - removeProvider(oldProvider); - } else { - throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); - } - } - - LocationProviderProxy proxy = new LocationProviderProxy(name, provider); - addProvider(proxy); - updateProvidersLocked(); - if (LocationManager.NETWORK_PROVIDER.equals(name)) { - mNetworkLocationProvider = proxy; - } - - // notify provider of current network state - proxy.updateNetworkState(mNetworkState, null); - } - } - - public void installGeocodeProvider(IGeocodeProvider provider) { - if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission"); - } - - mGeocodeProvider = provider; - } - private boolean isAllowedBySettingsLocked(String provider) { if (mEnabledProviders.contains(provider)) { return true; @@ -1313,7 +1293,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } /** - * @return null if the provider does not exits + * @return null if the provider does not exist * @throws SecurityException if the provider is not allowed to be * accessed by the caller */ @@ -1332,7 +1312,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private Bundle _getProviderInfoLocked(String provider) { LocationProviderProxy p = mProvidersByName.get(provider); - if (p == null) { + if (p == null || !p.isEnabled()) { return null; } @@ -1552,10 +1532,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) - || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { synchronized (mLock) { int uidList[] = null; - if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); } else { uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)}; @@ -1618,7 +1598,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run synchronized (mLock) { for (int i = mProviders.size() - 1; i >= 0; i--) { LocationProviderProxy provider = mProviders.get(i); - if (provider.requiresNetwork()) { + if (provider.isEnabled() && provider.requiresNetwork()) { provider.updateNetworkState(mNetworkState, info); } } @@ -1669,13 +1649,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run public String getFromLocation(double latitude, double longitude, int maxResults, GeocoderParams params, List<Address> addrs) { if (mGeocodeProvider != null) { - try { - return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, - params, addrs); - } catch (RemoteException e) { - Log.e(TAG, "getFromLocation failed", e); - mGeocodeProvider = null; - } + return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, + params, addrs); } return null; } @@ -1687,14 +1662,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run GeocoderParams params, List<Address> addrs) { if (mGeocodeProvider != null) { - try { - return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, - lowerLeftLongitude, upperRightLatitude, upperRightLongitude, - maxResults, params, addrs); - } catch (RemoteException e) { - Log.e(TAG, "getFromLocationName failed", e); - mGeocodeProvider = null; - } + return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, + lowerLeftLongitude, upperRightLatitude, upperRightLongitude, + maxResults, params, addrs); } return null; } @@ -1737,7 +1707,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (mProvidersByName.get(name) != null) { throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); } - addProvider(new LocationProviderProxy(name, provider)); + addProvider(new LocationProviderProxy(mContext, name, provider)); mMockProviders.put(name, provider); mLastKnownLocation.put(name, null); updateProvidersLocked(); diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 6382646..456244a 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -23,29 +23,34 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; -import android.os.IMountService; -import android.os.IMountServiceListener; -import android.os.MountServiceResultCode; +import android.os.storage.IMountService; +import android.os.storage.IMountServiceListener; +import android.os.storage.StorageResultCode; import android.os.RemoteException; import android.os.IBinder; import android.os.Environment; import android.os.ServiceManager; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.UEventObserver; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import java.util.ArrayList; +import java.util.HashSet; import java.io.File; import java.io.FileReader; /** - * MountService implements an to the mount service daemon - * @hide + * MountService implements back-end services for platform storage + * management. + * @hide - Applications should use android.os.storage.StorageManager + * to access the MountService. */ class MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks { + private static final boolean LOCAL_LOGD = false; private static final String TAG = "MountService"; @@ -109,45 +114,40 @@ class MountService extends IMountService.Stub private PackageManagerService mPms; private boolean mUmsEnabling; private ArrayList<MountServiceBinderListener> mListeners; + private boolean mBooted; + private boolean mReady; /** - * Constructs a new MountService instance - * - * @param context Binder context for this service + * Private hash of currently mounted secure containers. */ - public MountService(Context context) { - mContext = context; - - // XXX: This will go away soon in favor of IMountServiceObserver - mPms = (PackageManagerService) ServiceManager.getService("package"); - - // Register a BOOT_COMPLETED handler so that we can start - // our NativeDaemonConnector. We defer the startup so that we don't - // start processing events before we ought-to - mContext.registerReceiver(mBroadcastReceiver, - new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + private HashSet<String> mAsecMountSet = new HashSet<String>(); - mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector"); - mListeners = new ArrayList<MountServiceBinderListener>(); + private void waitForReady() { + while (mReady == false) { + for (int retries = 5; retries > 0; retries--) { + if (mReady) { + return; + } + SystemClock.sleep(1000); + } + Log.w(TAG, "Waiting too long for mReady!"); + } } - BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { - /* - * Vold does not run in the simulator, so fake out a mounted - * event to trigger MediaScanner - */ - if ("simulator".equals(SystemProperties.get("ro.product.device"))) { - updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED); - return; - } + mBooted = true; - Thread thread = new Thread( - mConnector, NativeDaemonConnector.class.getName()); - thread.start(); + String path = Environment.getExternalStorageDirectory().getPath(); + if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) { + int rc = doMountVolume(path); + if (rc != StorageResultCode.OperationSucceeded) { + Log.e(TAG, String.format("Boot-time mount failed (%d)", rc)); + } + } } } }; @@ -161,7 +161,7 @@ class MountService extends IMountService.Stub } public void binderDied() { - Log.d(TAG, "An IMountServiceListener has died!"); + if (LOCAL_LOGD) Log.d(TAG, "An IMountServiceListener has died!"); synchronized(mListeners) { mListeners.remove(this); mListener.asBinder().unlinkToDeath(this, 0); @@ -169,7 +169,7 @@ class MountService extends IMountService.Stub } } - int doShareUnshareVolume(String path, String method, boolean enable) { + private int doShareUnshareVolume(String path, String method, boolean enable) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); // TODO: Add support for multiple share methods @@ -182,9 +182,13 @@ class MountService extends IMountService.Stub */ String vs = getVolumeState(path); if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { - mUmsEnabling = enable; // Supress unmounted events - unmountVolume(path); - mUmsEnabling = false; // Unsupress unmounted events + mUmsEnabling = enable; // Override for isUsbMassStorageEnabled() + int rc = doUnmountVolume(path); + mUmsEnabling = false; // Clear override + if (rc != StorageResultCode.OperationSucceeded) { + Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc)); + return rc; + } } try { @@ -192,14 +196,14 @@ class MountService extends IMountService.Stub "volume %sshare %s %s", (enable ? "" : "un"), path, method)); } catch (NativeDaemonConnectorException e) { Log.e(TAG, "Failed to share/unshare", e); - return MountServiceResultCode.OperationFailedInternalError; + return StorageResultCode.OperationFailedInternalError; } /* * If we disabled UMS then mount the volume */ if (!enable) { - if (mountVolume(path) != MountServiceResultCode.OperationSucceeded) { + if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { Log.e(TAG, String.format( "Failed to remount %s after disabling share method %s", path, method)); /* @@ -210,15 +214,19 @@ class MountService extends IMountService.Stub } } - return MountServiceResultCode.OperationSucceeded; + return StorageResultCode.OperationSucceeded; } - void updatePublicVolumeState(String path, String state) { + private void updatePublicVolumeState(String path, String state) { if (!path.equals(Environment.getExternalStorageDirectory().getPath())) { Log.w(TAG, "Multiple volumes not currently supported"); return; } - Log.i(TAG, "State for {" + path + "} = {" + state + "}"); + + if (mLegacyState.equals(state)) { + Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state)); + return; + } String oldState = mLegacyState; mLegacyState = state; @@ -227,7 +235,7 @@ class MountService extends IMountService.Stub for (int i = mListeners.size() -1; i >= 0; i--) { MountServiceBinderListener bl = mListeners.get(i); try { - bl.mListener.onVolumeStateChanged("", path, oldState, state); + bl.mListener.onStorageStateChanged(path, oldState, state); } catch (RemoteException rex) { Log.e(TAG, "Listener dead"); mListeners.remove(i); @@ -270,11 +278,7 @@ class MountService extends IMountService.Stub if (st == VolumeState.NoMedia) { state = Environment.MEDIA_REMOVED; } else if (st == VolumeState.Idle) { - state = null; - int rc = mountVolume(path); - if (rc != MountServiceResultCode.OperationSucceeded) { - Log.e(TAG, String.format("Connection-mount failed (%d)", rc)); - } + state = Environment.MEDIA_UNMOUNTED; } else if (st == VolumeState.Mounted) { state = Environment.MEDIA_MOUNTED; Log.i(TAG, "Media already mounted on daemon connection"); @@ -294,23 +298,26 @@ class MountService extends IMountService.Stub } try { - boolean avail = getShareMethodAvailable("ums"); + boolean avail = doGetShareMethodAvailable("ums"); notifyShareAvailabilityChange("ums", avail); } catch (Exception ex) { Log.w(TAG, "Failed to get share availability"); } + /* + * Now that we've done our initialization, release + * the hounds! + */ + mReady = true; } }.start(); } /** - * * Callback from NativeDaemonConnector */ public boolean onEvent(int code, String raw, String[] cooked) { Intent in = null; - // Log.d(TAG, "event {" + raw + "}"); if (code == VoldResponseCode.VolumeStateChange) { /* * One of the volumes we're managing has changed state. @@ -347,34 +354,12 @@ class MountService extends IMountService.Stub Log.e(TAG, "Failed to parse major/minor", ex); } - synchronized (mListeners) { - for (int i = mListeners.size() -1; i >= 0; i--) { - MountServiceBinderListener bl = mListeners.get(i); - try { - if (code == VoldResponseCode.VolumeDiskInserted) { - bl.mListener.onMediaInserted(label, path, major, minor); - } else if (code == VoldResponseCode.VolumeDiskRemoved) { - bl.mListener.onMediaRemoved(label, path, major, minor, true); - } else if (code == VoldResponseCode.VolumeBadRemoval) { - bl.mListener.onMediaRemoved(label, path, major, minor, false); - } else { - Log.e(TAG, String.format("Unknown code {%d}", code)); - } - } catch (RemoteException rex) { - Log.e(TAG, "Listener dead"); - mListeners.remove(i); - } catch (Exception ex) { - Log.e(TAG, "Listener failed", ex); - } - } - } - if (code == VoldResponseCode.VolumeDiskInserted) { new Thread() { public void run() { try { int rc; - if ((rc = mountVolume(path)) != MountServiceResultCode.OperationSucceeded) { + if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { Log.w(TAG, String.format("Insertion mount failed (%d)", rc)); } } catch (Exception ex) { @@ -417,7 +402,7 @@ class MountService extends IMountService.Stub return true; } - void notifyVolumeStateChange(String label, String path, int oldState, int newState) { + private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { String vs = getVolumeState(path); Intent in = null; @@ -471,7 +456,144 @@ class MountService extends IMountService.Stub } } - void notifyShareAvailabilityChange(String method, final boolean avail) { + private boolean doGetShareMethodAvailable(String method) { + ArrayList<String> rsp = mConnector.doCommand("share status " + method); + + for (String line : rsp) { + String []tok = line.split(" "); + int code; + try { + code = Integer.parseInt(tok[0]); + } catch (NumberFormatException nfe) { + Log.e(TAG, String.format("Error parsing code %s", tok[0])); + return false; + } + if (code == VoldResponseCode.ShareStatusResult) { + if (tok[2].equals("available")) + return true; + return false; + } else { + Log.e(TAG, String.format("Unexpected response code %d", code)); + return false; + } + } + Log.e(TAG, "Got an empty response"); + return false; + } + + private int doMountVolume(String path) { + int rc = StorageResultCode.OperationSucceeded; + + try { + mConnector.doCommand(String.format("volume mount %s", path)); + } catch (NativeDaemonConnectorException e) { + /* + * Mount failed for some reason + */ + Intent in = null; + int code = e.getCode(); + if (code == VoldResponseCode.OpFailedNoMedia) { + /* + * Attempt to mount but no media inserted + */ + rc = StorageResultCode.OperationFailedNoMedia; + } else if (code == VoldResponseCode.OpFailedMediaBlank) { + /* + * Media is blank or does not contain a supported filesystem + */ + updatePublicVolumeState(path, Environment.MEDIA_NOFS); + in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); + rc = StorageResultCode.OperationFailedMediaBlank; + } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { + /* + * Volume consistency check failed + */ + updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); + in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); + rc = StorageResultCode.OperationFailedMediaCorrupt; + } else { + rc = StorageResultCode.OperationFailedInternalError; + } + + /* + * Send broadcast intent (if required for the failure) + */ + if (in != null) { + mContext.sendBroadcast(in); + } + } + + return rc; + } + + private int doUnmountVolume(String path) { + if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { + return VoldResponseCode.OpFailedVolNotMounted; + } + + // Notify PackageManager of potential media removal and deal with + // return code later on. The caller of this api should be aware or have been + // notified that the applications installed on the media will be killed. + mPms.updateExternalMediaStatus(false); + try { + mConnector.doCommand(String.format("volume unmount %s", path)); + return StorageResultCode.OperationSucceeded; + } catch (NativeDaemonConnectorException e) { + // Don't worry about mismatch in PackageManager since the + // call back will handle the status changes any way. + int code = e.getCode(); + if (code == VoldResponseCode.OpFailedVolNotMounted) { + return StorageResultCode.OperationFailedVolumeNotMounted; + } else { + return StorageResultCode.OperationFailedInternalError; + } + } + } + + private int doFormatVolume(String path) { + try { + String cmd = String.format("volume format %s", path); + mConnector.doCommand(cmd); + return StorageResultCode.OperationSucceeded; + } catch (NativeDaemonConnectorException e) { + int code = e.getCode(); + if (code == VoldResponseCode.OpFailedNoMedia) { + return StorageResultCode.OperationFailedNoMedia; + } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { + return StorageResultCode.OperationFailedMediaCorrupt; + } else { + return StorageResultCode.OperationFailedInternalError; + } + } + } + + private boolean doGetVolumeShared(String path, String method) { + String cmd = String.format("volume shared %s %s", path, method); + ArrayList<String> rsp = mConnector.doCommand(cmd); + + for (String line : rsp) { + String []tok = line.split(" "); + int code; + try { + code = Integer.parseInt(tok[0]); + } catch (NumberFormatException nfe) { + Log.e(TAG, String.format("Error parsing code %s", tok[0])); + return false; + } + if (code == VoldResponseCode.ShareEnabledResult) { + if (tok[2].equals("enabled")) + return true; + return false; + } else { + Log.e(TAG, String.format("Unexpected response code %d", code)); + return false; + } + } + Log.e(TAG, "Got an empty response"); + return false; + } + + private void notifyShareAvailabilityChange(String method, final boolean avail) { if (!method.equals("ums")) { Log.w(TAG, "Ignoring unsupported share method {" + method + "}"); return; @@ -481,7 +603,7 @@ class MountService extends IMountService.Stub for (int i = mListeners.size() -1; i >= 0; i--) { MountServiceBinderListener bl = mListeners.get(i); try { - bl.mListener.onShareAvailabilityChanged(method, avail); + bl.mListener.onUsbMassStorageConnectionChanged(avail); } catch (RemoteException rex) { Log.e(TAG, "Listener dead"); mListeners.remove(i); @@ -491,22 +613,55 @@ class MountService extends IMountService.Stub } } - Intent intent; - if (avail) { - intent = new Intent(Intent.ACTION_UMS_CONNECTED); - } else { - intent = new Intent(Intent.ACTION_UMS_DISCONNECTED); + if (mBooted == true) { + Intent intent; + if (avail) { + intent = new Intent(Intent.ACTION_UMS_CONNECTED); + } else { + intent = new Intent(Intent.ACTION_UMS_DISCONNECTED); + } + mContext.sendBroadcast(intent); } - mContext.sendBroadcast(intent); } - void validatePermission(String perm) { + private void validatePermission(String perm) { if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException(String.format("Requires %s permission", perm)); } } /** + * Constructs a new MountService instance + * + * @param context Binder context for this service + */ + public MountService(Context context) { + mContext = context; + + /* + * Vold does not run in the simulator, so fake out a mounted + * event to trigger MediaScanner + */ + if ("simulator".equals(SystemProperties.get("ro.product.device"))) { + updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED); + return; + } + + // XXX: This will go away soon in favor of IMountServiceObserver + mPms = (PackageManagerService) ServiceManager.getService("package"); + + mContext.registerReceiver(mBroadcastReceiver, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + + mListeners = new ArrayList<MountServiceBinderListener>(); + + mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector"); + mReady = false; + Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName()); + thread.start(); + } + + /** * Exposed API calls below here */ @@ -549,7 +704,7 @@ class MountService extends IMountService.Stub * the UMS host could have dirty FAT cache entries * yet to flush. */ - if (unshareVolume(path, "ums") != MountServiceResultCode.OperationSucceeded) { + if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) { Log.e(TAG, "UMS disable on shutdown failed"); } } else if (state.equals(Environment.MEDIA_CHECKING)) { @@ -577,75 +732,30 @@ class MountService extends IMountService.Stub /* * If the media is mounted, then gracefully unmount it. */ - if (unmountVolume(path) != MountServiceResultCode.OperationSucceeded) { + if (doUnmountVolume(path) != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to unmount media for shutdown"); } } } - public String[] getShareMethodList() { - String[] rdata = new String[1]; - rdata[0] = "ums"; - return rdata; - } + public boolean isUsbMassStorageConnected() { + waitForReady(); - public boolean getShareMethodAvailable(String method) { - ArrayList<String> rsp = mConnector.doCommand("share status " + method); - - for (String line : rsp) { - String []tok = line.split(" "); - int code; - try { - code = Integer.parseInt(tok[0]); - } catch (NumberFormatException nfe) { - Log.e(TAG, String.format("Error parsing code %s", tok[0])); - return false; - } - if (code == VoldResponseCode.ShareStatusResult) { - if (tok[2].equals("available")) - return true; - return false; - } else { - Log.e(TAG, String.format("Unexpected response code %d", code)); - return false; - } + if (mUmsEnabling) { + return true; } - Log.e(TAG, "Got an empty response"); - return false; + return doGetShareMethodAvailable("ums"); } - public int shareVolume(String path, String method) { - return doShareUnshareVolume(path, method, true); - } + public int setUsbMassStorageEnabled(boolean enable) { + waitForReady(); - public int unshareVolume(String path, String method) { - return doShareUnshareVolume(path, method, false); + return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable); } - public boolean getVolumeShared(String path, String method) { - String cmd = String.format("volume shared %s %s", path, method); - ArrayList<String> rsp = mConnector.doCommand(cmd); - - for (String line : rsp) { - String []tok = line.split(" "); - int code; - try { - code = Integer.parseInt(tok[0]); - } catch (NumberFormatException nfe) { - Log.e(TAG, String.format("Error parsing code %s", tok[0])); - return false; - } - if (code == VoldResponseCode.ShareEnabledResult) { - if (tok[2].equals("enabled")) - return true; - return false; - } else { - Log.e(TAG, String.format("Unexpected response code %d", code)); - return false; - } - } - Log.e(TAG, "Got an empty response"); - return false; + public boolean isUsbMassStorageEnabled() { + waitForReady(); + return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums"); } /** @@ -664,103 +774,38 @@ class MountService extends IMountService.Stub return mLegacyState; } - - /** - * Attempt to mount external media - */ public int mountVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); - int rc = MountServiceResultCode.OperationSucceeded; - - try { - mConnector.doCommand(String.format("volume mount %s", path)); - } catch (NativeDaemonConnectorException e) { - /* - * Mount failed for some reason - */ - Intent in = null; - int code = e.getCode(); - if (code == VoldResponseCode.OpFailedNoMedia) { - /* - * Attempt to mount but no media inserted - */ - rc = MountServiceResultCode.OperationFailedNoMedia; - } else if (code == VoldResponseCode.OpFailedMediaBlank) { - /* - * Media is blank or does not contain a supported filesystem - */ - updatePublicVolumeState(path, Environment.MEDIA_NOFS); - in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); - rc = MountServiceResultCode.OperationFailedMediaBlank; - } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { - /* - * Volume consistency check failed - */ - updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); - in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); - rc = MountServiceResultCode.OperationFailedMediaCorrupt; - } else { - rc = MountServiceResultCode.OperationFailedInternalError; - } - - /* - * Send broadcast intent (if required for the failure) - */ - if (in != null) { - mContext.sendBroadcast(in); - } - } - - return rc; + waitForReady(); + return doMountVolume(path); } - /** - * Attempt to unmount external media to prepare for eject - */ public int unmountVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + waitForReady(); - try { - mConnector.doCommand(String.format("volume unmount %s", path)); - return MountServiceResultCode.OperationSucceeded; - } catch (NativeDaemonConnectorException e) { - int code = e.getCode(); - if (code == VoldResponseCode.OpFailedVolNotMounted) { - return MountServiceResultCode.OperationFailedVolumeNotMounted; - } else { - return MountServiceResultCode.OperationFailedInternalError; - } - } + return doUnmountVolume(path); } - /** - * Synchronously formats a volume - * - * @param path The volume path to format - * @return Error code from MountServiceResultCode - */ public int formatVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); + waitForReady(); - try { - String cmd = String.format("volume format %s", path); - mConnector.doCommand(cmd); - return MountServiceResultCode.OperationSucceeded; - } catch (NativeDaemonConnectorException e) { - int code = e.getCode(); - if (code == VoldResponseCode.OpFailedNoMedia) { - return MountServiceResultCode.OperationFailedNoMedia; - } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { - return MountServiceResultCode.OperationFailedMediaCorrupt; - } else { - return MountServiceResultCode.OperationFailedInternalError; - } + return doFormatVolume(path); + } + + private void warnOnNotMounted() { + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + Log.w(TAG, "getSecureContainerList() called when storage not mounted"); } } public String[] getSecureContainerList() { validatePermission(android.Manifest.permission.ASEC_ACCESS); + waitForReady(); + warnOnNotMounted(); + try { return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult); } catch (NativeDaemonConnectorException e) { @@ -771,82 +816,124 @@ class MountService extends IMountService.Stub public int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid) { validatePermission(android.Manifest.permission.ASEC_CREATE); + waitForReady(); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid); try { mConnector.doCommand(cmd); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; } return rc; } public int finalizeSecureContainer(String id) { validatePermission(android.Manifest.permission.ASEC_CREATE); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; try { mConnector.doCommand(String.format("asec finalize %s", id)); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; } return rc; } public int destroySecureContainer(String id) { validatePermission(android.Manifest.permission.ASEC_DESTROY); + waitForReady(); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; try { mConnector.doCommand(String.format("asec destroy %s", id)); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; } return rc; } public int mountSecureContainer(String id, String key, int ownerUid) { validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); + waitForReady(); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; String cmd = String.format("asec mount %s %s %d", id, key, ownerUid); try { mConnector.doCommand(cmd); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; + } + + if (rc == StorageResultCode.OperationSucceeded) { + synchronized (mAsecMountSet) { + mAsecMountSet.add(id); + } } return rc; } public int unmountSecureContainer(String id) { validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); + waitForReady(); + warnOnNotMounted(); + + synchronized (mAsecMountSet) { + if (!mAsecMountSet.contains(id)) { + return StorageResultCode.OperationFailedVolumeNotMounted; + } + } - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; String cmd = String.format("asec unmount %s", id); try { mConnector.doCommand(cmd); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; + } + + if (rc == StorageResultCode.OperationSucceeded) { + synchronized (mAsecMountSet) { + mAsecMountSet.remove(id); + } } return rc; } + public boolean isSecureContainerMounted(String id) { + validatePermission(android.Manifest.permission.ASEC_ACCESS); + waitForReady(); + warnOnNotMounted(); + + synchronized (mAsecMountSet) { + return mAsecMountSet.contains(id); + } + } + public int renameSecureContainer(String oldId, String newId) { validatePermission(android.Manifest.permission.ASEC_RENAME); + waitForReady(); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; String cmd = String.format("asec rename %s %s", oldId, newId); try { mConnector.doCommand(cmd); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; } return rc; } public String getSecureContainerPath(String id) { validatePermission(android.Manifest.permission.ASEC_ACCESS); + waitForReady(); + warnOnNotMounted(); + ArrayList<String> rsp = mConnector.doCommand("asec path " + id); for (String line : rsp) { diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 9a066d3..cf083c0 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -21,7 +21,6 @@ import android.net.LocalSocket; import android.os.Environment; import android.os.SystemClock; import android.os.SystemProperties; -import android.util.Config; import android.util.Log; import java.io.IOException; @@ -41,6 +40,7 @@ import java.util.concurrent.LinkedBlockingQueue; * protocol. */ final class NativeDaemonConnector implements Runnable { + private static final boolean LOCAL_LOGD = false; private BlockingQueue<String> mResponseQueue; private OutputStream mOutputStream; @@ -110,7 +110,7 @@ final class NativeDaemonConnector implements Runnable { for (int i = 0; i < count; i++) { if (buffer[i] == 0) { String event = new String(buffer, start, i - start); -// Log.d(TAG, "Got packet {" + event + "}"); + if (LOCAL_LOGD) Log.d(TAG, String.format("RCV <- {%s}", event)); String[] tokens = event.split(" "); try { @@ -177,7 +177,7 @@ final class NativeDaemonConnector implements Runnable { */ private void sendCommand(String command, String argument) { synchronized (this) { - Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}"); + if (LOCAL_LOGD) Log.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); if (mOutputStream == null) { Log.e(TAG, "No connection to daemon", new IllegalStateException()); } else { @@ -210,7 +210,7 @@ final class NativeDaemonConnector implements Runnable { while (!complete) { try { String line = mResponseQueue.take(); - Log.d(TAG, String.format("RSP -> {%s}", line)); + if (LOCAL_LOGD) Log.d(TAG, String.format("RSP <- {%s}", line)); String[] tokens = line.split(" "); try { code = Integer.parseInt(tokens[0]); @@ -250,13 +250,18 @@ final class NativeDaemonConnector implements Runnable { String[] rdata = new String[rsp.size()-1]; int idx = 0; - for (String line : rsp) { + for (int i = 0; i < rsp.size(); i++) { + String line = rsp.get(i); try { String[] tok = line.split(" "); int code = Integer.parseInt(tok[0]); if (code == expectedResponseCode) { rdata[idx++] = line.substring(tok[0].length() + 1); } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { + if (LOCAL_LOGD) Log.d(TAG, String.format("List terminated with {%s}", line)); + if (i != rsp.size()) { + Log.w(TAG, String.format("Recv'd %d lines after list term", (rsp.size()-i))); + } return rdata; } else { throw new NativeDaemonConnectorException( diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 02a0401..ad8ab84 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -50,6 +50,7 @@ import android.os.Message; import android.os.Power; import android.os.Process; import android.os.RemoteException; +import android.os.storage.StorageManager; import android.os.SystemProperties; import android.os.Vibrator; import android.provider.Settings; @@ -330,9 +331,9 @@ class NotificationManagerService extends INotificationManager.Stub updateAdbNotification(); } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) - || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { String pkgList[] = null; - if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else { Uri uri = intent.getData(); @@ -406,6 +407,10 @@ class NotificationManagerService extends INotificationManager.Stub mSound.setUsesWakeLock(context); mToastQueue = new ArrayList<ToastRecord>(); mHandler = new WorkerHandler(); + + StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); + sm.registerListener(new com.android.internal.app.StorageNotification(context)); + mStatusBarService = statusBar; statusBar.setNotificationCallbacks(mNotificationCallbacks); @@ -440,7 +445,7 @@ class NotificationManagerService extends INotificationManager.Stub filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); mContext.registerReceiver(mIntentReceiver, filter); - IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mIntentReceiver, sdFilter); SettingsObserver observer = new SettingsObserver(mHandler); diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java index dbd1826..9551db5 100644 --- a/services/java/com/android/server/PackageManagerBackupAgent.java +++ b/services/java/com/android/server/PackageManagerBackupAgent.java @@ -40,6 +40,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Set; /** * We back up the signatures of each package so that during a system restore, @@ -100,6 +101,20 @@ public class PackageManagerBackupAgent extends BackupAgent { return mRestoredSignatures.get(packageName); } + + public Set<String> getRestoredPackages() { + if (mRestoredSignatures == null) { + Log.w(TAG, "getRestoredPackages() before metadata read!"); + return null; + } + + // This is technically the set of packages on the originating handset + // that had backup agents at all, not limited to the set of packages + // that had actually contributed a restore dataset, but it's a + // close enough approximation for our purposes and does not require any + // additional involvement by the transport to obtain. + return mRestoredSignatures.keySet(); + } // The backed up data is the signature block for each app, keyed by // the package name. diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 387f139..10bf851 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -20,6 +20,7 @@ import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; import com.android.common.FastXmlSerializer; import com.android.common.XmlUtils; +import com.android.server.JournaledFile; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -74,7 +75,7 @@ import android.os.Environment; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; -import android.os.MountServiceResultCode; +import android.os.storage.StorageResultCode; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.ServiceManager; @@ -148,6 +149,10 @@ class PackageManagerService extends IPackageManager.Stub { static final int SCAN_NEW_INSTALL = 1<<4; static final int SCAN_NO_PATHS = 1<<5; + static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( + "com.android.defcontainer", + "com.android.defcontainer.DefaultContainerService"); + final HandlerThread mHandlerThread = new HandlerThread("PackageManager", Process.THREAD_PRIORITY_BACKGROUND); final PackageHandler mHandler; @@ -298,6 +303,7 @@ class PackageManagerService extends IPackageManager.Stub { static final int END_COPY = 4; static final int INIT_COPY = 5; static final int MCS_UNBIND = 6; + static final int START_CLEANING_PACKAGE = 7; // Delay time in millisecs static final int BROADCAST_DELAY = 10 * 1000; private ServiceConnection mDefContainerConn = new ServiceConnection() { @@ -328,9 +334,7 @@ class PackageManagerService extends IPackageManager.Stub { case INIT_COPY: { InstallArgs args = (InstallArgs) msg.obj; args.createCopyFile(); - Intent service = new Intent().setComponent(new ComponentName( - "com.android.defcontainer", - "com.android.defcontainer.DefaultContainerService")); + Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); if (mContainerService != null) { // No need to add to pending list. Use remote stub directly handleStartCopy(args); @@ -405,6 +409,15 @@ class PackageManagerService extends IPackageManager.Stub { } break; } + case START_CLEANING_PACKAGE: { + String packageName = (String)msg.obj; + synchronized (mPackages) { + if (!mSettings.mPackagesToBeCleaned.contains(packageName)) { + mSettings.mPackagesToBeCleaned.add(packageName); + } + } + startCleaningPackages(); + } break; } } @@ -2111,6 +2124,12 @@ class PackageManagerService extends IPackageManager.Stub { File file = new File(dir, files[i]); PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode); + // Don't mess around with apps in system partition. + if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0) { + // Delete the apk + Log.w(TAG, "Cleaning up failed install of " + file); + file.delete(); + } } } @@ -2353,6 +2372,13 @@ class PackageManagerService extends IPackageManager.Stub { private PackageParser.Package scanPackageLI( PackageParser.Package pkg, int parseFlags, int scanMode) { File scanFile = new File(pkg.mScanPath); + if (scanFile == null || pkg.applicationInfo.sourceDir == null || + pkg.applicationInfo.publicSourceDir == null) { + // Bail out. The resource and code paths haven't been set. + Log.w(TAG, " Code and resource paths haven't been set correctly"); + mLastScanError = PackageManager.INSTALL_FAILED_INVALID_APK; + return null; + } mScanningPath = scanFile; if (pkg == null) { mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; @@ -2810,6 +2836,9 @@ class PackageManagerService extends IPackageManager.Stub { mSettings.insertPackageSettingLP(pkgSetting, pkg); // Add the new setting to mPackages mPackages.put(pkg.applicationInfo.packageName, pkg); + // Make sure we don't accidentally delete its data. + mSettings.mPackagesToBeCleaned.remove(pkgName); + int N = pkg.providers.size(); StringBuilder r = null; int i; @@ -4005,7 +4034,47 @@ class PackageManagerService extends IPackageManager.Stub { } } } + + public String nextPackageToClean(String lastPackage) { + synchronized (mPackages) { + if (!mMediaMounted) { + // If the external storage is no longer mounted at this point, + // the caller may not have been able to delete all of this + // packages files and can not delete any more. Bail. + return null; + } + if (lastPackage != null) { + mSettings.mPackagesToBeCleaned.remove(lastPackage); + } + return mSettings.mPackagesToBeCleaned.size() > 0 + ? mSettings.mPackagesToBeCleaned.get(0) : null; + } + } + void schedulePackageCleaning(String packageName) { + mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE, packageName)); + } + + void startCleaningPackages() { + synchronized (mPackages) { + if (!mMediaMounted) { + return; + } + if (mSettings.mPackagesToBeCleaned.size() <= 0) { + return; + } + } + Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE); + intent.setComponent(DEFAULT_CONTAINER_COMPONENT); + IActivityManager am = ActivityManagerNative.getDefault(); + if (am != null) { + try { + am.startService(null, intent, null); + } catch (RemoteException e) { + } + } + } + private final class AppDirObserver extends FileObserver { public AppDirObserver(String path, int mask, boolean isrom) { super(path, mask); @@ -4959,69 +5028,82 @@ class PackageManagerService extends IPackageManager.Stub { File tmpPackageFile = new File(args.getCodePath()); boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0); boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0); - boolean replacingExistingPackage = false; + boolean replace = false; int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE | (newInstall ? SCAN_NEW_INSTALL : 0); // Result object to be returned res.returnCode = PackageManager.INSTALL_SUCCEEDED; - main_flow: try { - // Retrieve PackageSettings and parse package - int parseFlags = PackageParser.PARSE_CHATTY | - (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) | - (onSd ? PackageParser.PARSE_ON_SDCARD : 0); - parseFlags |= mDefParseFlags; - PackageParser pp = new PackageParser(tmpPackageFile.getPath()); - pp.setSeparateProcesses(mSeparateProcesses); - final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, - null, mMetrics, parseFlags); - if (pkg == null) { - res.returnCode = pp.getParseError(); - break main_flow; - } - String pkgName = res.name = pkg.packageName; - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) { - if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) { - res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY; - break main_flow; - } + // Retrieve PackageSettings and parse package + int parseFlags = PackageParser.PARSE_CHATTY | + (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) | + (onSd ? PackageParser.PARSE_ON_SDCARD : 0); + parseFlags |= mDefParseFlags; + PackageParser pp = new PackageParser(tmpPackageFile.getPath()); + pp.setSeparateProcesses(mSeparateProcesses); + final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, + null, mMetrics, parseFlags); + if (pkg == null) { + res.returnCode = pp.getParseError(); + return; + } + String pkgName = res.name = pkg.packageName; + if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) { + if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) { + res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY; + return; } - if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) { - res.returnCode = pp.getParseError(); - break main_flow; + } + if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) { + res.returnCode = pp.getParseError(); + return; + } + // Some preinstall checks + if (forwardLocked && onSd) { + // Make sure forward locked apps can only be installed + // on internal storage + Log.w(TAG, "Cannot install protected apps on sdcard"); + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; + return; + } + // Get rid of all references to package scan path via parser. + pp = null; + String oldCodePath = null; + boolean systemApp = false; + synchronized (mPackages) { + // Check if installing already existing package + if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0 + && mPackages.containsKey(pkgName)) { + replace = true; } - - // Get rid of all references to package scan path via parser. - pp = null; - String oldCodePath = null; - synchronized (mPackages) { - //check if installing already existing package - if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0 - && mPackages.containsKey(pkgName)) { - replacingExistingPackage = true; - } - PackageSetting ps = mSettings.mPackages.get(pkgName); - if (ps != null) { - oldCodePath = mSettings.mPackages.get(pkgName).codePathString; + PackageSetting ps = mSettings.mPackages.get(pkgName); + if (ps != null) { + oldCodePath = mSettings.mPackages.get(pkgName).codePathString; + if (ps.pkg != null && ps.pkg.applicationInfo != null) { + systemApp = (ps.pkg.applicationInfo.flags & + ApplicationInfo.FLAG_SYSTEM) != 0; } } + } - if (!args.doRename(res.returnCode, pkgName, oldCodePath)) { - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - // Set application objects path explicitly after the rename - setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); - if(replacingExistingPackage) { - replacePackageLI(pkg, parseFlags, scanMode, - installerPackageName, res); - } else { - installNewPackageLI(pkg, parseFlags, scanMode, - installerPackageName,res); - } - } finally { - if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - } + if (systemApp && onSd) { + // Disable updates to system apps on sdcard + Log.w(TAG, "Cannot install updates to system apps on sdcard"); + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; + return; + } + if (!args.doRename(res.returnCode, pkgName, oldCodePath)) { + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + return; + } + // Set application objects path explicitly after the rename + setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); + if(replace) { + replacePackageLI(pkg, parseFlags, scanMode, + installerPackageName, res); + } else { + installNewPackageLI(pkg, parseFlags, scanMode, + installerPackageName,res); } } @@ -5198,7 +5280,6 @@ class PackageManagerService extends IPackageManager.Stub { * persisting settings for later use * sending a broadcast if necessary */ - private boolean deletePackageX(String packageName, boolean sendBroadCast, boolean deleteCodeAndResources, int flags) { PackageRemovedInfo info = new PackageRemovedInfo(); @@ -5290,6 +5371,7 @@ class PackageManagerService extends IPackageManager.Stub { File dataDir = new File(pkg.applicationInfo.dataDir); dataDir.delete(); } + schedulePackageCleaning(packageName); synchronized (mPackages) { if (outInfo != null) { outInfo.removedUid = mSettings.removePackageLP(packageName); @@ -5302,7 +5384,7 @@ class PackageManagerService extends IPackageManager.Stub { mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids); } // Save settings now - mSettings.writeLP (); + mSettings.writeLP(); } } @@ -6745,6 +6827,7 @@ class PackageManagerService extends IPackageManager.Stub { private static final class Settings { private final File mSettingsFilename; private final File mBackupSettingsFilename; + private final File mPackageListFilename; private final HashMap<String, PackageSetting> mPackages = new HashMap<String, PackageSetting>(); // List of replaced system applications @@ -6791,6 +6874,10 @@ class PackageManagerService extends IPackageManager.Stub { final HashMap<String, BasePermission> mPermissionTrees = new HashMap<String, BasePermission>(); + // Packages that have been uninstalled and still need their external + // storage data deleted. + final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>(); + private final StringBuilder mReadMessages = new StringBuilder(); private static final class PendingPackage extends PackageSettingBase { @@ -6822,6 +6909,7 @@ class PackageManagerService extends IPackageManager.Stub { -1, -1); mSettingsFilename = new File(systemDir, "packages.xml"); mBackupSettingsFilename = new File(systemDir, "packages-backup.xml"); + mPackageListFilename = new File(systemDir, "packages.list"); } PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage, @@ -7354,6 +7442,14 @@ class PackageManagerService extends IPackageManager.Stub { serializer.endTag(null, "shared-user"); } + if (mPackagesToBeCleaned.size() > 0) { + for (int i=0; i<mPackagesToBeCleaned.size(); i++) { + serializer.startTag(null, "cleaning-package"); + serializer.attribute(null, "name", mPackagesToBeCleaned.get(i)); + serializer.endTag(null, "cleaning-package"); + } + } + serializer.endTag(null, "packages"); serializer.endDocument(); @@ -7369,6 +7465,61 @@ class PackageManagerService extends IPackageManager.Stub { |FileUtils.S_IRGRP|FileUtils.S_IWGRP |FileUtils.S_IROTH, -1, -1); + + // Write package list file now, use a JournaledFile. + // + File tempFile = new File(mPackageListFilename.toString() + ".tmp"); + JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile); + + str = new FileOutputStream(journal.chooseForWrite()); + try { + StringBuilder sb = new StringBuilder(); + for (PackageSetting pkg : mPackages.values()) { + ApplicationInfo ai = pkg.pkg.applicationInfo; + String dataPath = ai.dataDir; + boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + + // Avoid any application that has a space in its path + // or that is handled by the system. + if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID) + continue; + + // we store on each line the following information for now: + // + // pkgName - package name + // userId - application-specific user id + // debugFlag - 0 or 1 if the package is debuggable. + // dataPath - path to package's data path + // + // NOTE: We prefer not to expose all ApplicationInfo flags for now. + // + // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS + // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES: + // system/core/run-as/run-as.c + // + sb.setLength(0); + sb.append(ai.packageName); + sb.append(" "); + sb.append((int)ai.uid); + sb.append(isDebug ? " 1 " : " 0 "); + sb.append(dataPath); + sb.append("\n"); + str.write(sb.toString().getBytes()); + } + str.flush(); + str.close(); + journal.commit(); + } + catch (Exception e) { + journal.rollback(); + } + + FileUtils.setPermissions(mPackageListFilename.toString(), + FileUtils.S_IRUSR|FileUtils.S_IWUSR + |FileUtils.S_IRGRP|FileUtils.S_IWGRP + |FileUtils.S_IROTH, + -1, -1); + return; } catch(XmlPullParserException e) { @@ -7376,7 +7527,7 @@ class PackageManagerService extends IPackageManager.Stub { } catch(java.io.IOException e) { Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e); } - // Clean up partially written file + // Clean up partially written files if (mSettingsFilename.exists()) { if (!mSettingsFilename.delete()) { Log.i(TAG, "Failed to clean up mangled file: " + mSettingsFilename); @@ -7386,7 +7537,7 @@ class PackageManagerService extends IPackageManager.Stub { } void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg) - throws java.io.IOException { + throws java.io.IOException { serializer.startTag(null, "updated-package"); serializer.attribute(null, "name", pkg.name); serializer.attribute(null, "codePath", pkg.codePathString); @@ -7424,7 +7575,7 @@ class PackageManagerService extends IPackageManager.Stub { } void writePackage(XmlSerializer serializer, final PackageSetting pkg) - throws java.io.IOException { + throws java.io.IOException { serializer.startTag(null, "package"); serializer.attribute(null, "name", pkg.name); serializer.attribute(null, "codePath", pkg.codePathString); @@ -7614,6 +7765,11 @@ class PackageManagerService extends IPackageManager.Stub { readPreferredActivitiesLP(parser); } else if(tagName.equals("updated-package")) { readDisabledSysPackageLP(parser); + } else if (tagName.equals("cleaning-package")) { + String name = parser.getAttributeValue(null, "name"); + if (name != null) { + mPackagesToBeCleaned.add(name); + } } else { Log.w(TAG, "Unknown element under <packages>: " + parser.getName()); @@ -7739,7 +7895,7 @@ class PackageManagerService extends IPackageManager.Stub { } private void readDisabledSysPackageLP(XmlPullParser parser) - throws XmlPullParserException, IOException { + throws XmlPullParserException, IOException { String name = parser.getAttributeValue(null, "name"); String codePathStr = parser.getAttributeValue(null, "codePath"); String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); @@ -8269,17 +8425,17 @@ class PackageManagerService extends IPackageManager.Stub { int rc = mountService.createSecureContainer( pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID); - if (rc != MountServiceResultCode.OperationSucceeded) { + if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, String.format("Failed to create container (%d)", rc)); rc = mountService.destroySecureContainer(pkgName); - if (rc != MountServiceResultCode.OperationSucceeded) { + if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, String.format("Failed to cleanup container (%d)", rc)); return null; } rc = mountService.createSecureContainer( pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID); - if (rc != MountServiceResultCode.OperationSucceeded) { + if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, String.format("Failed to create container (2nd try) (%d)", rc)); return null; } @@ -8299,7 +8455,7 @@ class PackageManagerService extends IPackageManager.Stub { int rc = getMountService().mountSecureContainer(pkgName, sdEncKey, ownerUid); - if (rc != MountServiceResultCode.OperationSucceeded) { + if (rc != StorageResultCode.OperationSucceeded) { Log.i(TAG, "Failed to mount container for pkg : " + pkgName + " rc : " + rc); return null; } @@ -8310,7 +8466,7 @@ class PackageManagerService extends IPackageManager.Stub { private boolean unMountSdDir(String pkgName) { // STOPSHIP unmount directory int rc = getMountService().unmountSecureContainer(pkgName); - if (rc != MountServiceResultCode.OperationSucceeded) { + if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to unmount : " + pkgName + " with rc " + rc); return false; } @@ -8334,7 +8490,7 @@ class PackageManagerService extends IPackageManager.Stub { private boolean finalizeSdDir(String pkgName) { int rc = getMountService().finalizeSecureContainer(pkgName); - if (rc != MountServiceResultCode.OperationSucceeded) { + if (rc != StorageResultCode.OperationSucceeded) { Log.i(TAG, "Failed to finalize container for pkg : " + pkgName); return false; } @@ -8343,7 +8499,7 @@ class PackageManagerService extends IPackageManager.Stub { private boolean destroySdDir(String pkgName) { int rc = getMountService().destroySecureContainer(pkgName); - if (rc != MountServiceResultCode.OperationSucceeded) { + if (rc != StorageResultCode.OperationSucceeded) { Log.i(TAG, "Failed to destroy container for pkg : " + pkgName); return false; } @@ -8409,19 +8565,21 @@ class PackageManagerService extends IPackageManager.Stub { } public void updateExternalMediaStatus(final boolean mediaStatus) { - final boolean DEBUG = true; - if (DEBUG) Log.i(TAG, "updateExterMediaStatus::"); - if (mediaStatus == mMediaMounted) { - return; - } - mMediaMounted = mediaStatus; - // Queue up an async operation since the package installation may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - updateExternalMediaStatusInner(mediaStatus); + synchronized (mPackages) { + if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + + mediaStatus+", mMediaMounted=" + mMediaMounted); + if (mediaStatus == mMediaMounted) { + return; } - }); + mMediaMounted = mediaStatus; + // Queue up an async operation since the package installation may take a little while. + mHandler.post(new Runnable() { + public void run() { + mHandler.removeCallbacks(this); + updateExternalMediaStatusInner(mediaStatus); + } + }); + } } void updateExternalMediaStatusInner(boolean mediaStatus) { @@ -8432,9 +8590,6 @@ class PackageManagerService extends IPackageManager.Stub { HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>(); int uidList[] = new int[list.length]; int num = 0; - for (int i = 0; i < uidList.length; i++) { - uidList[i] = Process.LAST_APPLICATION_UID; - } synchronized (mPackages) { Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD); for (String cid : list) { @@ -8456,24 +8611,35 @@ class PackageManagerService extends IPackageManager.Stub { processCids.put(args, ps.codePathString); int uid = ps.userId; if (uid != -1) { - int idx = Arrays.binarySearch(uidList, uid); - if (idx < 0) { - uidList[-idx] = uid; - num++; - } + uidList[num++] = uid; } } } - int uidArr[] = uidList; - if ((num > 0) && (num < uidList.length)) { + int uidArr[] = null; + if (num > 0) { + // Sort uid list + Arrays.sort(uidList, 0, num); + // Throw away duplicates uidArr = new int[num]; - for (int i = 0; i < num; i++) { - uidArr[i] = uidList[i]; + uidArr[0] = uidList[0]; + int di = 0; + for (int i = 1; i < num; i++) { + if (uidList[i-1] != uidList[i]) { + uidArr[di++] = uidList[i]; + } + } + if (true) { + for (int j = 0; j < num; j++) { + Log.i(TAG, "uidArr[" + j + "]=" + uidArr[j]); + } } } if (mediaStatus) { + if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages"); loadMediaPackages(processCids, uidArr); + startCleaningPackages(); } else { + if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages"); unloadMediaPackages(processCids, uidArr); } } @@ -8486,9 +8652,11 @@ class PackageManagerService extends IPackageManager.Stub { Bundle extras = new Bundle(); extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList.toArray(new String[size])); - extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); - String action = mediaStatus ? Intent.ACTION_MEDIA_RESOURCES_AVAILABLE - : Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE; + if (uidArr != null) { + extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); + } + String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE + : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; sendPackageBroadcast(action, null, extras); } } @@ -8497,10 +8665,11 @@ class PackageManagerService extends IPackageManager.Stub { ArrayList<String> pkgList = new ArrayList<String>(); Set<SdInstallArgs> keys = processCids.keySet(); for (SdInstallArgs args : keys) { - String cid = args.cid; String codePath = processCids.get(args); + if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install pkg : " + + args.cid + " from " + args.cachePath); if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) { - Log.i(TAG, "Failed to install package: " + codePath + " from sdcard"); + Log.e(TAG, "Failed to install package: " + codePath + " from sdcard"); continue; } // Parse package @@ -8511,7 +8680,8 @@ class PackageManagerService extends IPackageManager.Stub { final PackageParser.Package pkg = pp.parsePackage(new File(codePath), codePath, mMetrics, parseFlags); if (pkg == null) { - Log.w(TAG, "Failed to install package : " + cid + " from sd card"); + Log.e(TAG, "Trying to install pkg : " + + args.cid + " from " + args.cachePath); continue; } setApplicationInfoPaths(pkg, codePath, codePath); @@ -8532,22 +8702,24 @@ class PackageManagerService extends IPackageManager.Stub { } } args.doPostInstall(retCode); - pkgList.add(pkg.packageName); } // Send broadcasts first - sendResourcesChangedBroadcast(true, pkgList, uidArr); - Runtime.getRuntime().gc(); - // If something failed do we clean up here or next install? + if (pkgList.size() > 0) { + sendResourcesChangedBroadcast(true, pkgList, uidArr); + Runtime.getRuntime().gc(); + // If something failed do we clean up here or next install? + } } void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) { + if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages"); ArrayList<String> pkgList = new ArrayList<String>(); + ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>(); Set<SdInstallArgs> keys = processCids.keySet(); for (SdInstallArgs args : keys) { String cid = args.cid; String pkgName = args.getPackageName(); - // STOPSHIP Send broadcast to apps to remove references - // STOPSHIP Unmount package + if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName); // Delete package internally PackageRemovedInfo outInfo = new PackageRemovedInfo(); synchronized (mInstallLock) { @@ -8557,14 +8729,17 @@ class PackageManagerService extends IPackageManager.Stub { pkgList.add(pkgName); } else { Log.e(TAG, "Failed to delete pkg from sdcard : " + pkgName); + failedList.add(args); } } } // Send broadcasts - sendResourcesChangedBroadcast(false, pkgList, uidArr); - Runtime.getRuntime().gc(); + if (pkgList.size() > 0) { + sendResourcesChangedBroadcast(false, pkgList, uidArr); + Runtime.getRuntime().gc(); + } // Do clean up. Just unmount - for (SdInstallArgs args : keys) { + for (SdInstallArgs args : failedList) { synchronized (mInstallLock) { args.doPostDeleteLI(false); } diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 1e7dd99..1ccae86 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -41,7 +41,7 @@ import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; -import android.os.IMountService; +import android.os.storage.IMountService; import android.os.IPowerManager; import android.os.LocalPowerManager; import android.os.Power; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ee1cc8d..6e9c21b 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -273,19 +273,22 @@ class ServerThread extends Thread { } try { - Log.i(TAG, "Notification Manager"); - notification = new NotificationManagerService(context, statusBar, lights); - ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification); + /* + * NotificationManagerService is dependant on MountService, + * (for media / usb notifications) so we must start MountService first. + */ + Log.i(TAG, "Mount Service"); + ServiceManager.addService("mount", new MountService(context)); } catch (Throwable e) { - Log.e(TAG, "Failure starting Notification Manager", e); + Log.e(TAG, "Failure starting Mount Service", e); } try { - // MountService must start after NotificationManagerService - Log.i(TAG, "Mount Service"); - ServiceManager.addService("mount", new MountService(context)); + Log.i(TAG, "Notification Manager"); + notification = new NotificationManagerService(context, statusBar, lights); + ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification); } catch (Throwable e) { - Log.e(TAG, "Failure starting Mount Service", e); + Log.e(TAG, "Failure starting Notification Manager", e); } try { diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 88aadbd..b57e543 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -5465,7 +5465,6 @@ public class WindowManagerService extends IWindowManager.Stub curFocus = mCurrentFocus; // cache the paused state at ctor time as well if (theFocus == null || theFocus.mToken == null) { - Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!"); focusPaused = false; } else { focusPaused = theFocus.mToken.paused; @@ -5478,7 +5477,7 @@ public class WindowManagerService extends IWindowManager.Stub + " fin=" + finished + " gfw=" + gotFirstWindow + " ed=" + eventDispatching + " tts=" + timeToSwitch + " wf=" + wasFrozen + " fp=" + focusPaused - + " mcf=" + mCurrentFocus + "}}"; + + " mcf=" + curFocus + "}}"; } }; private DispatchState mDispatchState = null; @@ -5651,10 +5650,11 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (this) { Log.w(TAG, "Key dispatching timed out sending to " + (targetWin != null ? targetWin.mAttrs.getTitle() - : "<null>")); + : "<null>: no window ready for key dispatch")); // NOSHIP debugging - Log.w(TAG, "Dispatch state: " + mDispatchState); - Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin)); + Log.w(TAG, "Previous dispatch state: " + mDispatchState); + Log.w(TAG, "Current dispatch state: " + + new DispatchState(nextKey, targetWin)); // END NOSHIP //dump(); if (targetWin != null) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 5e6881c..98ded37 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -11941,7 +11941,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen intent.getAction()); if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) - || Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction()) + || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction()) || uidRemoved) { if (checkComponentPermission( android.Manifest.permission.BROADCAST_PACKAGE_REMOVED, @@ -11960,7 +11960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } else { // If resources are unvailble just force stop all // those packages and flush the attribute cache as well. - if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) { String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (list != null && (list.length > 0)) { for (String pkg : list) { @@ -12146,7 +12146,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen skipPackages = new String[] { pkgName }; } } - } else if (intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(intent.getAction())) { + } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) { skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } if (skipPackages != null && (skipPackages.length > 0)) { diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java index 55041fb..c7c3335 100644 --- a/services/java/com/android/server/status/StatusBarService.java +++ b/services/java/com/android/server/status/StatusBarService.java @@ -1813,14 +1813,14 @@ public class StatusBarService extends IStatusBar.Stub filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); filter.addDataScheme("package"); mContext.registerReceiver(this, filter); - IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(this, sdFilter); } @Override public void onReceive(Context context, Intent intent) { String pkgList[] = null; - if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else { Uri data = intent.getData(); |