IntentForwarderActivity.java revision 0e2b73f6858479ca963bd53c49f8955d98f14869
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 17package com.android.internal.app; 18 19import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; 20 21import android.app.Activity; 22import android.app.ActivityManagerNative; 23import android.app.ActivityThread; 24import android.app.AppGlobals; 25import android.app.admin.DevicePolicyManager; 26import android.content.Context; 27import android.content.Intent; 28import android.content.pm.IPackageManager; 29import android.content.pm.UserInfo; 30import android.os.Bundle; 31import android.os.Process; 32import android.os.RemoteException; 33import android.os.UserHandle; 34import android.os.UserManager; 35import android.util.Slog; 36import android.widget.Toast; 37 38import 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 */ 45public 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 int targetUserId; 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 targetUserId = UserHandle.USER_OWNER; 67 } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { 68 userMessageId = com.android.internal.R.string.forward_intent_to_work; 69 targetUserId = getManagedProfile(); 70 } else { 71 Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly"); 72 userMessageId = -1; 73 targetUserId = UserHandle.USER_NULL; 74 } 75 if (targetUserId == UserHandle.USER_NULL) { 76 // This covers the case where there is no managed profile. 77 finish(); 78 return; 79 } 80 Intent newIntent = new Intent(intentReceived); 81 newIntent.setComponent(null); 82 // Apps should not be allowed to target a specific package in the target user. 83 newIntent.setPackage(null); 84 newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT 85 |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); 86 int callingUserId = getUserId(); 87 88 if (canForward(newIntent, targetUserId)) { 89 if (newIntent.getAction().equals(Intent.ACTION_CHOOSER)) { 90 Intent innerIntent = (Intent) newIntent.getParcelableExtra(Intent.EXTRA_INTENT); 91 innerIntent.setContentUserHint(callingUserId); 92 } else { 93 newIntent.setContentUserHint(callingUserId); 94 } 95 96 final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser( 97 newIntent, MATCH_DEFAULT_ONLY, targetUserId); 98 99 // Only show a disclosure if this is a normal (non-OS) app 100 final boolean shouldShowDisclosure = 101 !UserHandle.isSameApp(ri.activityInfo.applicationInfo.uid, Process.SYSTEM_UID); 102 103 try { 104 startActivityAsCaller(newIntent, null, targetUserId); 105 } catch (RuntimeException e) { 106 int launchedFromUid = -1; 107 String launchedFromPackage = "?"; 108 try { 109 launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid( 110 getActivityToken()); 111 launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage( 112 getActivityToken()); 113 } catch (RemoteException ignored) { 114 } 115 116 Slog.wtf(TAG, "Unable to launch as UID " + launchedFromUid + " package " 117 + launchedFromPackage + ", while running in " 118 + ActivityThread.currentProcessName(), e); 119 } 120 121 if (shouldShowDisclosure) { 122 Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show(); 123 } 124 } else { 125 Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user " 126 + callingUserId + " to user " + targetUserId); 127 } 128 finish(); 129 } 130 131 boolean canForward(Intent intent, int targetUserId) { 132 IPackageManager ipm = AppGlobals.getPackageManager(); 133 if (intent.getAction().equals(Intent.ACTION_CHOOSER)) { 134 // The EXTRA_INITIAL_INTENTS may not be allowed to be forwarded. 135 if (intent.hasExtra(Intent.EXTRA_INITIAL_INTENTS)) { 136 Slog.wtf(TAG, "An chooser intent with extra initial intents cannot be forwarded to" 137 + " a different user"); 138 return false; 139 } 140 if (intent.hasExtra(Intent.EXTRA_REPLACEMENT_EXTRAS)) { 141 Slog.wtf(TAG, "A chooser intent with replacement extras cannot be forwarded to a" 142 + " different user"); 143 return false; 144 } 145 intent = (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT); 146 } 147 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); 148 if (intent.getSelector() != null) { 149 intent = intent.getSelector(); 150 } 151 try { 152 return ipm.canForwardTo(intent, resolvedType, getUserId(), 153 targetUserId); 154 } catch (RemoteException e) { 155 Slog.e(TAG, "PackageManagerService is dead?"); 156 return false; 157 } 158 } 159 160 /** 161 * Returns the userId of the managed profile for this device or UserHandle.USER_NULL if there is 162 * no managed profile. 163 * 164 * TODO: Remove the assumption that there is only one managed profile 165 * on the device. 166 */ 167 private int getManagedProfile() { 168 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); 169 List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER); 170 for (UserInfo userInfo : relatedUsers) { 171 if (userInfo.isManagedProfile()) return userInfo.id; 172 } 173 Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE 174 + " has been called, but there is no managed profile"); 175 return UserHandle.USER_NULL; 176 } 177} 178