diff options
Diffstat (limited to 'services/core/java')
11 files changed, 387 insertions, 123 deletions
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index f0fc399..417f18d 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -48,6 +48,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.storage.MountServiceInternal; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; @@ -60,6 +61,7 @@ import android.util.Xml; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IAppOpsCallback; +import com.android.internal.os.Zygote; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; @@ -245,6 +247,34 @@ public class AppOpsService extends IAppOpsService.Stub { scheduleFastWriteLocked(); } } + + MountServiceInternal mountServiceInternal = LocalServices.getService( + MountServiceInternal.class); + mountServiceInternal.addExternalStoragePolicy( + new MountServiceInternal.ExternalStorageMountPolicy() { + @Override + public int getMountMode(int uid, String packageName) { + if (Process.isIsolated(uid)) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid, + packageName) != AppOpsManager.MODE_ALLOWED) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid, + packageName) != AppOpsManager.MODE_ALLOWED) { + return Zygote.MOUNT_EXTERNAL_READ; + } + return Zygote.MOUNT_EXTERNAL_WRITE; + } + + @Override + public boolean hasExternalStorage(int uid, String packageName) { + final int mountMode = getMountMode(uid, packageName); + return mountMode == Zygote.MOUNT_EXTERNAL_READ + || mountMode == Zygote.MOUNT_EXTERNAL_WRITE; + } + }); } public void packageRemoved(int uid, String packageName) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 9b1e26a..eb74ab0 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -563,8 +563,9 @@ public class ConnectivityService extends IConnectivityManager.Stub final DetailedState state = nai.networkInfo.getDetailedState(); for (int type = 0; type < mTypeLists.length; type++) { final ArrayList<NetworkAgentInfo> list = mTypeLists[type]; + final boolean contains = (list != null && list.contains(nai)); final boolean isFirst = (list != null && list.size() > 0 && nai == list.get(0)); - if (isFirst || isDefault) { + if (isFirst || (contains && isDefault)) { maybeLogBroadcast(nai, state, type, isDefault); sendLegacyNetworkBroadcast(nai, state, type); } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index da552dd..bc61c3d 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -68,6 +68,8 @@ import android.os.storage.IMountService; import android.os.storage.IMountServiceListener; import android.os.storage.IMountShutdownObserver; import android.os.storage.IObbActionListener; +import android.os.storage.MountServiceInternal; +import android.os.storage.MountServiceInternal.ExternalStorageMountPolicy; import android.os.storage.OnObbStateChangeListener; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; @@ -127,6 +129,7 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -307,16 +310,6 @@ class MountService extends IMountService.Stub @GuardedBy("mLock") private String mMoveTargetUuid; - private DiskInfo findDiskById(String id) { - synchronized (mLock) { - final DiskInfo disk = mDisks.get(id); - if (disk != null) { - return disk; - } - } - throw new IllegalArgumentException("No disk found for ID " + id); - } - private VolumeInfo findVolumeByIdOrThrow(String id) { synchronized (mLock) { final VolumeInfo vol = mVolumes.get(id); @@ -456,6 +449,9 @@ class MountService extends IMountService.Stub /** Map from raw paths to {@link ObbState}. */ final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); + // Not guarded by a lock. + private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl(); + class ObbState implements IBinder.DeathRecipient { public ObbState(String rawPath, String canonicalPath, int callingUid, IObbActionListener token, int nonce) { @@ -807,7 +803,7 @@ class MountService extends IMountService.Stub for (int i = 0; i < mVolumes.size(); i++) { final VolumeInfo vol = mVolumes.valueAt(i); if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) { - final StorageVolume userVol = vol.buildStorageVolume(mContext, userId); + final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); final String envState = VolumeInfo.getEnvironmentForState(vol.getState()); @@ -1250,7 +1246,7 @@ class MountService extends IMountService.Stub // user-specific broadcasts. for (int userId : mStartedUsers) { if (vol.isVisibleToUser(userId)) { - final StorageVolume userVol = vol.buildStorageVolume(mContext, userId); + final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv, @@ -1370,6 +1366,8 @@ class MountService extends IMountService.Stub readSettingsLocked(); } + LocalServices.addService(MountServiceInternal.class, mMountServiceInternal); + /* * Create the connection to vold with a maximum queue of twice the * amount of containers we'd ever expect to have. This keeps an @@ -1787,27 +1785,28 @@ class MountService extends IMountService.Stub } } - @Override - public void remountUid(int uid) { - enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + private void remountUidExternalStorage(int uid, int mode) { waitForReady(); - final int mountExternal = mPms.getMountExternalMode(uid); - final String mode; - if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) { - mode = "default"; - } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) { - mode = "read"; - } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) { - mode = "write"; - } else { - mode = "none"; + String modeName = "none"; + switch (mode) { + case Zygote.MOUNT_EXTERNAL_DEFAULT: { + modeName = "default"; + } break; + + case Zygote.MOUNT_EXTERNAL_READ: { + modeName = "read"; + } break; + + case Zygote.MOUNT_EXTERNAL_WRITE: { + modeName = "write"; + } break; } try { - mConnector.execute("volume", "remount_uid", uid, mode); + mConnector.execute("volume", "remount_uid", uid, modeName); } catch (NativeDaemonConnectorException e) { - Slog.w(TAG, "Failed to remount UID " + uid + " as " + mode + ": " + e); + Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e); } } @@ -2598,15 +2597,20 @@ class MountService extends IMountService.Stub } @Override - public StorageVolume[] getVolumeList(int userId) { + public StorageVolume[] getVolumeList(int uid, String packageName) { final ArrayList<StorageVolume> res = new ArrayList<>(); boolean foundPrimary = false; + final int userId = UserHandle.getUserId(uid); + final boolean reportUnmounted = !mMountServiceInternal.hasExternalStorage( + uid, packageName); + synchronized (mLock) { for (int i = 0; i < mVolumes.size(); i++) { final VolumeInfo vol = mVolumes.valueAt(i); if (vol.isVisibleToUser(userId)) { - final StorageVolume userVol = vol.buildStorageVolume(mContext, userId); + final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, + reportUnmounted); if (vol.isPrimary()) { res.add(0, userVol); foundPrimary = true; @@ -3379,4 +3383,50 @@ class MountService extends IMountService.Stub mCryptConnector.monitor(); } } + + private final class MountServiceInternalImpl extends MountServiceInternal { + // Not guarded by a lock. + private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies = + new CopyOnWriteArrayList<>(); + + @Override + public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) { + // No locking - CopyOnWriteArrayList + mPolicies.add(policy); + } + + @Override + public void onExternalStoragePolicyChanged(int uid, String packageName) { + final int mountMode = getExternalStorageMountMode(uid, packageName); + remountUidExternalStorage(uid, mountMode); + } + + @Override + public int getExternalStorageMountMode(int uid, String packageName) { + // No locking - CopyOnWriteArrayList + int mountMode = Integer.MAX_VALUE; + for (ExternalStorageMountPolicy policy : mPolicies) { + final int policyMode = policy.getMountMode(uid, packageName); + if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + mountMode = Math.min(mountMode, policyMode); + } + if (mountMode == Integer.MAX_VALUE) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + return mountMode; + } + + public boolean hasExternalStorage(int uid, String packageName) { + // No locking - CopyOnWriteArrayList + for (ExternalStorageMountPolicy policy : mPolicies) { + final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName); + if (!policyHasStorage) { + return false; + } + } + return true; + } + } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 36d64aa..a06bb30 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -16,6 +16,7 @@ package com.android.server; +import android.Manifest; import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.BroadcastReceiver; @@ -360,12 +361,20 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + " callback.asBinder=" + callback.asBinder()); } - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.READ_PHONE_STATE, null); + try { + mContext.enforceCallingPermission( + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "addOnSubscriptionsChangedListener"); + // SKIP checking for run-time permission since obtained PRIVILEGED + } catch (SecurityException e) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_PHONE_STATE, + "addOnSubscriptionsChangedListener"); - if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), - callingPackage) != AppOpsManager.MODE_ALLOWED) { - return; + if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return; + } } Record r; @@ -471,9 +480,15 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { checkListenerPermission(events); if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { - if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), - callingPackage) != AppOpsManager.MODE_ALLOWED) { - return; + try { + mContext.enforceCallingPermission( + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); + // SKIP checking for run-time permission since obtained PRIVILEGED + } catch (SecurityException e) { + if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return; + } } } @@ -646,6 +661,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } private boolean canReadPhoneState(String callingPackage) { + if (mContext.checkCallingPermission( + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) == + PackageManager.PERMISSION_GRANTED) { + // SKIP checking for run-time permission since obtained PRIVILEGED + return true; + } boolean canReadPhoneState = mContext.checkCallingOrSelfPermission( android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; if (canReadPhoneState && @@ -1432,6 +1453,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); } + // Send broadcast twice, once for apps that have PRIVILEGED permission and once for those + // that have the runtime one + mContext.sendBroadcastAsUser(intent, UserHandle.ALL, + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE); mContext.sendBroadcastAsUser(intent, UserHandle.ALL, android.Manifest.permission.READ_PHONE_STATE, AppOpsManager.OP_READ_PHONE_STATE); @@ -1563,8 +1588,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.READ_PHONE_STATE, null); + try { + mContext.enforceCallingPermission( + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); + // SKIP checking for run-time permission since obtained PRIVILEGED + } catch (SecurityException e) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_PHONE_STATE, null); + } } if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6e94647..5bfca10 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -18,7 +18,10 @@ package com.android.server.am; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; +import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; +import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; +import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; @@ -62,6 +65,7 @@ import android.os.Trace; import android.os.TransactionTooLargeException; import android.os.WorkSource; import android.os.storage.IMountService; +import android.os.storage.MountServiceInternal; import android.os.storage.StorageManager; import android.service.voice.IVoiceInteractionSession; import android.util.ArrayMap; @@ -3219,7 +3223,10 @@ public final class ActivityManagerService extends ActivityManagerNative checkTime(startTime, "startProcess: getting gids from package manager"); final IPackageManager pm = AppGlobals.getPackageManager(); permGids = pm.getPackageGids(app.info.packageName, app.userId); - mountExternal = pm.getMountExternalMode(uid); + MountServiceInternal mountServiceInternal = LocalServices.getService( + MountServiceInternal.class); + mountExternal = mountServiceInternal.getExternalStorageMountMode(uid, + app.info.packageName); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 8c3a950..470bbb0 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2669,8 +2669,13 @@ final class ActivityStack { if (!r.finishing) { if (!mService.isSleeping()) { if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r); - requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, - "stop-no-history", false); + if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, + "stop-no-history", false)) { + // Activity was finished, no need to continue trying to schedule stop. + adjustFocusedActivityLocked(r, "stopActivityFinished"); + r.resumeKeyDispatchingLocked(); + return; + } } else { if (DEBUG_STATES) Slog.d(TAG_STATES, "Not finishing noHistory " + r + " on stop because we're just sleeping"); @@ -2963,6 +2968,7 @@ final class ActivityStack { r.state = ActivityState.FINISHING; if (mode == FINISH_IMMEDIATELY + || (mode == FINISH_AFTER_PAUSE && prevState == ActivityState.PAUSED) || prevState == ActivityState.STOPPED || prevState == ActivityState.INITIALIZING) { // If this activity is already stopped, we can just finish diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index 7a74729..e3c6037 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -29,6 +29,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Build; +import android.os.Debug; import android.os.UserHandle; import android.provider.CalendarContract; import android.provider.ContactsContract; @@ -174,7 +175,7 @@ final class DefaultPermissionGrantPolicy { synchronized (mService.mPackages) { for (PackageParser.Package pkg : mService.mPackages.values()) { - if (!isSysComponentOrPersistentPrivApp(pkg) + if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg) || !doesPackageSupportRuntimePermissions(pkg)) { continue; } @@ -344,7 +345,6 @@ final class DefaultPermissionGrantPolicy { Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION); PackageParser.Package cbrPackage = getDefaultSystemHandlerActivityPackageLPr(cbrIntent, userId); - if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) { grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, false, userId); } @@ -625,8 +625,9 @@ final class DefaultPermissionGrantPolicy { private PackageParser.Package getDefaultSystemHandlerActivityPackageLPr( Intent intent, int userId) { - List<ResolveInfo> handlers = mService.queryIntentActivities(intent, - intent.resolveType(mService.mContext.getContentResolver()), 0, userId); + List<ResolveInfo> handlers = mService.mActivities.queryIntent(intent, + intent.resolveType(mService.mContext.getContentResolver()), + PackageManager.GET_DISABLED_COMPONENTS, userId); final int handlerCount = handlers.size(); for (int i = 0; i < handlerCount; i++) { ResolveInfo handler = handlers.get(i); @@ -650,8 +651,9 @@ final class DefaultPermissionGrantPolicy { for (String syncAdapterPackageName : syncAdapterPackageNames) { homeIntent.setPackage(syncAdapterPackageName); - List<ResolveInfo> homeActivities = mService.queryIntentActivities(homeIntent, - homeIntent.resolveType(mService.mContext.getContentResolver()), 0, userId); + List<ResolveInfo> homeActivities = mService.mActivities.queryIntent(homeIntent, + homeIntent.resolveType(mService.mContext.getContentResolver()), + PackageManager.GET_DISABLED_COMPONENTS, userId); if (!homeActivities.isEmpty()) { continue; } @@ -681,7 +683,7 @@ final class DefaultPermissionGrantPolicy { private PackageParser.Package getSystemPackageLPr(String packageName) { PackageParser.Package pkg = getPackageLPr(packageName); if (pkg != null && pkg.isSystemApp()) { - return !isSysComponentOrPersistentPrivApp(pkg) ? pkg : null; + return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null; } return null; } @@ -730,11 +732,16 @@ final class DefaultPermissionGrantPolicy { } } - private static boolean isSysComponentOrPersistentPrivApp(PackageParser.Package pkg) { - return UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID - || ((pkg.applicationInfo.privateFlags - & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0 - && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0); + private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageParser.Package pkg) { + if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) { + return true; + } + if ((pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0 + || (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) { + return false; + } + return PackageManagerService.compareSignatures(mService.mPlatformPackage.mSignatures, + pkg.mSignatures) == PackageManager.SIGNATURE_MATCH; } private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bfb803d..ef9bc8b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -62,6 +62,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST; import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING; import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; +import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageParser.isApkFile; import static android.os.Process.PACKAGE_INFO_GID; @@ -143,10 +144,10 @@ import android.content.pm.VerifierInfo; import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.net.Uri; +import android.os.Debug; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.Debug; import android.os.Environment; import android.os.Environment.UserEnvironment; import android.os.FileUtils; @@ -166,6 +167,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.IMountService; +import android.os.storage.MountServiceInternal; import android.os.storage.StorageEventListener; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; @@ -284,7 +286,7 @@ public class PackageManagerService extends IPackageManager.Stub { static final boolean DEBUG_PREFERRED = false; static final boolean DEBUG_UPGRADE = false; static final boolean DEBUG_DOMAIN_VERIFICATION = false; - private static final boolean DEBUG_BACKUP = true; + private static final boolean DEBUG_BACKUP = false; private static final boolean DEBUG_INSTALL = false; private static final boolean DEBUG_REMOVE = false; private static final boolean DEBUG_BROADCASTS = false; @@ -2727,23 +2729,6 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } - @Override - public int getMountExternalMode(int uid) { - if (Process.isIsolated(uid)) { - return Zygote.MOUNT_EXTERNAL_NONE; - } else { - if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) { - return Zygote.MOUNT_EXTERNAL_DEFAULT; - } else if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) { - return Zygote.MOUNT_EXTERNAL_WRITE; - } else if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) { - return Zygote.MOUNT_EXTERNAL_READ; - } else { - return Zygote.MOUNT_EXTERNAL_DEFAULT; - } - } - } - static PermissionInfo generatePermissionInfo( BasePermission bp, int flags) { if (bp.perm != null) { @@ -3461,13 +3446,15 @@ public class PackageManagerService extends IPackageManager.Stub { // Only need to do this if user is initialized. Otherwise it's a new user // and there are no processes running as the user yet and there's no need // to make an expensive call to remount processes for the changed permissions. - if ((READ_EXTERNAL_STORAGE.equals(name) - || WRITE_EXTERNAL_STORAGE.equals(name)) - && sUserManager.isInitialized(userId)) { + if (READ_EXTERNAL_STORAGE.equals(name) + || WRITE_EXTERNAL_STORAGE.equals(name)) { final long token = Binder.clearCallingIdentity(); try { - final StorageManager storage = mContext.getSystemService(StorageManager.class); - storage.remountUid(uid); + if (sUserManager.isInitialized(userId)) { + MountServiceInternal mountServiceInternal = LocalServices.getService( + MountServiceInternal.class); + mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName); + } } finally { Binder.restoreCallingIdentity(token); } @@ -4431,8 +4418,11 @@ public class PackageManagerService extends IPackageManager.Stub { // cross-profile app linking works only towards the parent. final UserInfo parent = getProfileParent(sourceUserId); synchronized(mPackages) { - return getCrossProfileDomainPreferredLpr(intent, resolvedType, 0, sourceUserId, - parent.id) != null; + CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr( + intent, resolvedType, 0, sourceUserId, parent.id); + return xpDomainInfo != null + && xpDomainInfo.bestDomainVerificationStatus != + INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; } } return false; @@ -4527,8 +4517,8 @@ public class PackageManagerService extends IPackageManager.Stub { } else if (result.size() <= 1) { return result; } - result = filterCandidatesWithDomainPreferredActivitiesLPr(flags, result, - xpDomainInfo); + result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result, + xpDomainInfo, userId); Collections.sort(result, mResolvePrioritySorter); } return result; @@ -4577,7 +4567,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (ps == null) { continue; } - int status = getDomainVerificationStatusLPr(ps, parentUserId); + long verificationState = getDomainVerificationStatusLPr(ps, parentUserId); + int status = (int)(verificationState >> 32); if (result == null) { result = new CrossProfileDomainInfo(); result.resolveInfo = @@ -4644,14 +4635,16 @@ public class PackageManagerService extends IPackageManager.Stub { return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS); } - private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr( - int flags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo) { + private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent, + int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo, + int userId) { + final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0; + if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) { - Slog.v("TAG", "Filtering results with preferred activities. Candidates count: " + + Slog.v(TAG, "Filtering results with preferred activities. Candidates count: " + candidates.size()); } - final int userId = UserHandle.getCallingUserId(); ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>(); ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>(); ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>(); @@ -4674,11 +4667,17 @@ public class PackageManagerService extends IPackageManager.Stub { continue; } // Try to get the status from User settings first - int status = getDomainVerificationStatusLPr(ps, userId); + long packedStatus = getDomainVerificationStatusLPr(ps, userId); + int status = (int)(packedStatus >> 32); + int linkGeneration = (int)(packedStatus & 0xFFFFFFFF); if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.i(TAG, " + always: " + info.activityInfo.packageName); + Slog.i(TAG, " + always: " + info.activityInfo.packageName + + " : linkgen=" + linkGeneration); } + // Use link-enabled generation as preferredOrder, i.e. + // prefer newly-enabled over earlier-enabled. + info.preferredOrder = linkGeneration; alwaysList.add(info); } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { if (DEBUG_DOMAIN_VERIFICATION) { @@ -4694,7 +4693,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } } - // First try to add the "always" resolution for the current user if there is any + // First try to add the "always" resolution(s) for the current user, if any if (alwaysList.size() > 0) { result.addAll(alwaysList); // if there is an "always" for the parent user, add it. @@ -4712,26 +4711,41 @@ public class PackageManagerService extends IPackageManager.Stub { result.add(xpDomainInfo.resolveInfo); } // Also add Browsers (all of them or only the default one) - if ((flags & MATCH_ALL) != 0) { + if ((matchFlags & MATCH_ALL) != 0) { result.addAll(matchAllList); } else { - // Try to add the Default Browser if we can + // Browser/generic handling case. If there's a default browser, go straight + // to that (but only if there is no other higher-priority match). final String defaultBrowserPackageName = getDefaultBrowserPackageName( UserHandle.myUserId()); - if (!TextUtils.isEmpty(defaultBrowserPackageName)) { - boolean defaultBrowserFound = false; - final int browserCount = matchAllList.size(); - for (int n=0; n<browserCount; n++) { - ResolveInfo browser = matchAllList.get(n); - if (browser.activityInfo.packageName.equals(defaultBrowserPackageName)) { - result.add(browser); - defaultBrowserFound = true; - break; + int maxMatchPrio = 0; + ResolveInfo defaultBrowserMatch = null; + final int numCandidates = matchAllList.size(); + for (int n = 0; n < numCandidates; n++) { + ResolveInfo info = matchAllList.get(n); + // track the highest overall match priority... + if (info.priority > maxMatchPrio) { + maxMatchPrio = info.priority; + } + // ...and the highest-priority default browser match + if (info.activityInfo.packageName.equals(defaultBrowserPackageName)) { + if (defaultBrowserMatch == null + || (defaultBrowserMatch.priority < info.priority)) { + if (debug) { + Slog.v(TAG, "Considering default browser match " + info); + } + defaultBrowserMatch = info; } } - if (!defaultBrowserFound) { - result.addAll(matchAllList); + } + if (defaultBrowserMatch != null + && defaultBrowserMatch.priority >= maxMatchPrio + && !TextUtils.isEmpty(defaultBrowserPackageName)) + { + if (debug) { + Slog.v(TAG, "Default browser match " + defaultBrowserMatch); } + result.add(defaultBrowserMatch); } else { result.addAll(matchAllList); } @@ -4755,15 +4769,19 @@ public class PackageManagerService extends IPackageManager.Stub { return result; } - private int getDomainVerificationStatusLPr(PackageSetting ps, int userId) { - int status = ps.getDomainVerificationStatusForUser(userId); + // Returns a packed value as a long: + // + // high 'int'-sized word: link status: undefined/ask/never/always. + // low 'int'-sized word: relative priority among 'always' results. + private long getDomainVerificationStatusLPr(PackageSetting ps, int userId) { + long result = ps.getDomainVerificationStatusForUser(userId); // if none available, get the master status - if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) { + if (result >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) { if (ps.getIntentFilterVerificationInfo() != null) { - status = ps.getIntentFilterVerificationInfo().getStatus(); + result = ((long)ps.getIntentFilterVerificationInfo().getStatus()) << 32; } } - return status; + return result; } private ResolveInfo querySkipCurrentProfileIntents( @@ -12959,7 +12977,7 @@ public class PackageManagerService extends IPackageManager.Stub { false, //hidden null, null, null, false, // blockUninstall - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED); + INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0); if (!isSystemApp(ps)) { if (ps.isAnyInstalled(sUserManager.getUserIds())) { // Other user still have this package installed, so all @@ -14435,6 +14453,33 @@ public class PackageManagerService extends IPackageManager.Stub { mInstallerService.systemReady(); mPackageDexOptimizer.systemReady(); + + MountServiceInternal mountServiceInternal = LocalServices.getService( + MountServiceInternal.class); + mountServiceInternal.addExternalStoragePolicy( + new MountServiceInternal.ExternalStorageMountPolicy() { + @Override + public int getMountMode(int uid, String packageName) { + if (Process.isIsolated(uid)) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) { + return Zygote.MOUNT_EXTERNAL_DEFAULT; + } + if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) { + return Zygote.MOUNT_EXTERNAL_DEFAULT; + } + if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) { + return Zygote.MOUNT_EXTERNAL_READ; + } + return Zygote.MOUNT_EXTERNAL_WRITE; + } + + @Override + public boolean hasExternalStorage(int uid, String packageName) { + return true; + } + }); } @Override @@ -14882,8 +14927,8 @@ public class PackageManagerService extends IPackageManager.Stub { pw.println(); count = 0; for (PackageSetting ps : allPackageSettings) { - final int status = ps.getDomainVerificationStatusForUser(userId); - if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) { + final long status = ps.getDomainVerificationStatusForUser(userId); + if (status >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) { continue; } pw.println(prefix + "Package: " + ps.name); diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 6f46f69..4faf75a 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -341,7 +341,8 @@ abstract class PackageSettingBase extends SettingBase { void setUserState(int userId, int enabled, boolean installed, boolean stopped, boolean notLaunched, boolean hidden, String lastDisableAppCaller, ArraySet<String> enabledComponents, - ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState) { + ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState, + int linkGeneration) { PackageUserState state = modifyUserState(userId); state.enabled = enabled; state.installed = installed; @@ -353,6 +354,7 @@ abstract class PackageSettingBase extends SettingBase { state.disabledComponents = disabledComponents; state.blockUninstall = blockUninstall; state.domainVerificationStatus = domainVerifState; + state.appLinkGeneration = linkGeneration; } ArraySet<String> getEnabledComponents(int userId) { @@ -449,12 +451,23 @@ abstract class PackageSettingBase extends SettingBase { verificationInfo = info; } - int getDomainVerificationStatusForUser(int userId) { - return readUserState(userId).domainVerificationStatus; + // Returns a packed value as a long: + // + // high 'int'-sized word: link status: undefined/ask/never/always. + // low 'int'-sized word: relative priority among 'always' results. + long getDomainVerificationStatusForUser(int userId) { + PackageUserState state = readUserState(userId); + long result = (long) state.appLinkGeneration; + result |= ((long) state.domainVerificationStatus) << 32; + return result; } - void setDomainVerificationStatusForUser(int status, int userId) { - modifyUserState(userId).domainVerificationStatus = status; + void setDomainVerificationStatusForUser(final int status, int generation, int userId) { + PackageUserState state = modifyUserState(userId); + state.domainVerificationStatus = status; + if (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { + state.appLinkGeneration = generation; + } } void clearDomainVerificationStatusForUser(int userId) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index bdcd714..312b7b3 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -87,6 +87,7 @@ import android.util.ArraySet; import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.Xml; import java.io.BufferedOutputStream; @@ -196,6 +197,7 @@ final class Settings { private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus"; private static final String ATTR_PACKAGE_NAME= "packageName"; private static final String ATTR_FINGERPRINT = "fingerprint"; + private static final String ATTR_APP_LINK_GENERATION = "app-link-generation"; private final Object mLock; @@ -294,6 +296,9 @@ final class Settings { // For every user, it is used to find the package name of the default Browser App. final SparseArray<String> mDefaultBrowserApp = new SparseArray<String>(); + // App-link priority tracking, per-user + final SparseIntArray mNextAppLinkGeneration = new SparseIntArray(); + final StringBuilder mReadMessages = new StringBuilder(); /** @@ -624,7 +629,7 @@ final class Settings { false, // hidden null, null, null, false, // blockUninstall - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED); + INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0); writePackageRestrictionsLPr(user.id); } } @@ -1051,7 +1056,7 @@ final class Settings { } return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; } - int status = ps.getDomainVerificationStatusForUser(userId); + int status = (int)(ps.getDomainVerificationStatusForUser(userId) >> 32); if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) { if (ps.getIntentFilterVerificationInfo() != null) { status = ps.getIntentFilterVerificationInfo().getStatus(); @@ -1060,7 +1065,7 @@ final class Settings { return status; } - boolean updateIntentFilterVerificationStatusLPw(String packageName, int status, int userId) { + boolean updateIntentFilterVerificationStatusLPw(String packageName, final int status, int userId) { // Update the status for the current package PackageSetting current = mPackages.get(packageName); if (current == null) { @@ -1070,7 +1075,15 @@ final class Settings { return false; } - current.setDomainVerificationStatusForUser(status, userId); + final int alwaysGeneration; + if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { + alwaysGeneration = mNextAppLinkGeneration.get(userId) + 1; + mNextAppLinkGeneration.put(userId, alwaysGeneration); + } else { + alwaysGeneration = 0; + } + + current.setDomainVerificationStatusForUser(status, alwaysGeneration, userId); return true; } @@ -1382,7 +1395,7 @@ final class Settings { false, // hidden null, null, null, false, // blockUninstall - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED); + INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0); } return; } @@ -1404,6 +1417,8 @@ final class Settings { return; } + int maxAppLinkGeneration = 0; + int outerDepth = parser.getDepth(); PackageSetting ps = null; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT @@ -1457,6 +1472,12 @@ final class Settings { PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED : Integer.parseInt(verifStateStr); + final String linkGenStr = parser.getAttributeValue(null, ATTR_APP_LINK_GENERATION); + final int linkGeneration = linkGenStr == null ? 0 : Integer.parseInt(linkGenStr); + if (linkGeneration > maxAppLinkGeneration) { + maxAppLinkGeneration = linkGeneration; + } + ArraySet<String> enabledComponents = null; ArraySet<String> disabledComponents = null; @@ -1478,7 +1499,7 @@ final class Settings { ps.setUserState(userId, enabled, installed, stopped, notLaunched, hidden, enabledCaller, enabledComponents, disabledComponents, blockUninstall, - verifState); + verifState, linkGeneration); } else if (tagName.equals("preferred-activities")) { readPreferredActivitiesLPw(parser, userId); } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) { @@ -1496,6 +1517,8 @@ final class Settings { str.close(); + mNextAppLinkGeneration.put(userId, maxAppLinkGeneration + 1); + } catch (XmlPullParserException e) { mReadMessages.append("Error reading: " + e.toString()); PackageManagerService.reportSettingsProblem(Log.ERROR, @@ -1749,6 +1772,10 @@ final class Settings { serializer.attribute(null, ATTR_DOMAIN_VERIFICATON_STATE, Integer.toString(ustate.domainVerificationStatus)); } + if (ustate.appLinkGeneration != 0) { + serializer.attribute(null, ATTR_APP_LINK_GENERATION, + Integer.toString(ustate.appLinkGeneration)); + } if (ustate.enabledComponents != null && ustate.enabledComponents.size() > 0) { serializer.startTag(null, TAG_ENABLED_COMPONENTS); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 87efb8d..9e41f70 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -44,6 +44,9 @@ import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiPlaybackClient; +import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioSystem; @@ -356,6 +359,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSystemReady; boolean mSystemBooted; boolean mHdmiPlugged; + HdmiControl mHdmiControl; IUiModeManager mUiModeManager; int mUiMode; int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; @@ -1212,6 +1216,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void handleShortPressOnHome() { + // Turn on the connected TV and switch HDMI input if we're a HDMI playback device. + getHdmiControl().turnOnTv(); + // If there's a dream running then use home to escape the dream // but don't actually go home. if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) { @@ -1223,6 +1230,46 @@ public class PhoneWindowManager implements WindowManagerPolicy { launchHomeFromHotKey(); } + /** + * Creates an accessor to HDMI control service that performs the operation of + * turning on TV (optional) and switching input to us. If HDMI control service + * is not available or we're not a HDMI playback device, the operation is no-op. + */ + private HdmiControl getHdmiControl() { + if (null == mHdmiControl) { + HdmiControlManager manager = (HdmiControlManager) mContext.getSystemService( + Context.HDMI_CONTROL_SERVICE); + HdmiPlaybackClient client = null; + if (manager != null) { + client = manager.getPlaybackClient(); + } + mHdmiControl = new HdmiControl(client); + } + return mHdmiControl; + } + + private static class HdmiControl { + private final HdmiPlaybackClient mClient; + + private HdmiControl(HdmiPlaybackClient client) { + mClient = client; + } + + public void turnOnTv() { + if (mClient == null) { + return; + } + mClient.oneTouchPlay(new OneTouchPlayCallback() { + @Override + public void onComplete(int result) { + if (result != HdmiControlManager.RESULT_SUCCESS) { + Log.w(TAG, "One touch play failed: " + result); + } + } + }); + } + } + private void handleLongPressOnHome(int deviceId) { if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) { mHomeConsumed = true; |