1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.app; 18 19 import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; 20 21 import android.app.Activity; 22 import android.app.ActivityManagerNative; 23 import android.app.ActivityThread; 24 import android.app.AppGlobals; 25 import android.app.admin.DevicePolicyManager; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.IPackageManager; 29 import android.content.pm.UserInfo; 30 import android.os.Bundle; 31 import android.os.Process; 32 import android.os.RemoteException; 33 import android.os.UserHandle; 34 import android.os.UserManager; 35 import android.util.Slog; 36 import android.widget.Toast; 37 38 import java.util.List; 39 40 /** 41 * This is used in conjunction with 42 * {@link DevicePolicyManager#addCrossProfileIntentFilter} to enable intents to 43 * be passed in and out of a managed profile. 44 */ 45 public class IntentForwarderActivity extends Activity { 46 47 public static String TAG = "IntentForwarderActivity"; 48 49 public static String FORWARD_INTENT_TO_USER_OWNER 50 = "com.android.internal.app.ForwardIntentToUserOwner"; 51 52 public static String FORWARD_INTENT_TO_MANAGED_PROFILE 53 = "com.android.internal.app.ForwardIntentToManagedProfile"; 54 55 @Override 56 protected void onCreate(Bundle savedInstanceState) { 57 super.onCreate(savedInstanceState); 58 Intent intentReceived = getIntent(); 59 60 String className = intentReceived.getComponent().getClassName(); 61 final UserHandle userDest; 62 final int userMessageId; 63 64 if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) { 65 userMessageId = com.android.internal.R.string.forward_intent_to_owner; 66 userDest = UserHandle.OWNER; 67 } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { 68 userMessageId = com.android.internal.R.string.forward_intent_to_work; 69 userDest = getManagedProfile(); 70 } else { 71 Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly"); 72 userMessageId = -1; 73 userDest = null; 74 } 75 if (userDest == null) { // This covers the case where there is no managed profile. 76 finish(); 77 return; 78 } 79 Intent newIntent = new Intent(intentReceived); 80 newIntent.setComponent(null); 81 // Apps should not be allowed to target a specific package in the target user. 82 newIntent.setPackage(null); 83 newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT 84 |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); 85 int callingUserId = getUserId(); 86 IPackageManager ipm = AppGlobals.getPackageManager(); 87 String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver()); 88 boolean canForward = false; 89 Intent selector = newIntent.getSelector(); 90 if (selector == null) { 91 selector = newIntent; 92 } 93 try { 94 canForward = ipm.canForwardTo(selector, resolvedType, callingUserId, 95 userDest.getIdentifier()); 96 } catch (RemoteException e) { 97 Slog.e(TAG, "PackageManagerService is dead?"); 98 } 99 if (canForward) { 100 newIntent.setContentUserHint(callingUserId); 101 102 final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser( 103 newIntent, MATCH_DEFAULT_ONLY, userDest.getIdentifier()); 104 105 // Only show a disclosure if this is a normal (non-OS) app 106 final boolean shouldShowDisclosure = 107 !UserHandle.isSameApp(ri.activityInfo.applicationInfo.uid, Process.SYSTEM_UID); 108 109 try { 110 startActivityAsCaller(newIntent, null, userDest.getIdentifier()); 111 } catch (RuntimeException e) { 112 int launchedFromUid = -1; 113 String launchedFromPackage = "?"; 114 try { 115 launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid( 116 getActivityToken()); 117 launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage( 118 getActivityToken()); 119 } catch (RemoteException ignored) { 120 } 121 122 Slog.wtf(TAG, "Unable to launch as UID " + launchedFromUid + " package " 123 + launchedFromPackage + ", while running in " 124 + ActivityThread.currentProcessName(), e); 125 } 126 127 if (shouldShowDisclosure) { 128 Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show(); 129 } 130 } else { 131 Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user " 132 + callingUserId + " to user " + userDest.getIdentifier()); 133 } 134 finish(); 135 } 136 137 /** 138 * Returns the managed profile for this device or null if there is no managed 139 * profile. 140 * 141 * TODO: Remove the assumption that there is only one managed profile 142 * on the device. 143 */ 144 private UserHandle getManagedProfile() { 145 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); 146 List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER); 147 for (UserInfo userInfo : relatedUsers) { 148 if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id); 149 } 150 Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE 151 + " has been called, but there is no managed profile"); 152 return null; 153 } 154 } 155