• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
onCreate(Bundle savedInstanceState)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             // Don't show the disclosure if next activity is ResolverActivity or ChooserActivity
100             // as those will already have shown work / personal as neccesary etc.
101             final boolean shouldShowDisclosure = ri == null || ri.activityInfo == null ||
102                     !"android".equals(ri.activityInfo.packageName) ||
103                     !(ResolverActivity.class.getName().equals(ri.activityInfo.name)
104                     || ChooserActivity.class.getName().equals(ri.activityInfo.name));
105 
106             try {
107                 startActivityAsCaller(newIntent, null, targetUserId);
108             } catch (RuntimeException e) {
109                 int launchedFromUid = -1;
110                 String launchedFromPackage = "?";
111                 try {
112                     launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
113                             getActivityToken());
114                     launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
115                             getActivityToken());
116                 } catch (RemoteException ignored) {
117                 }
118 
119                 Slog.wtf(TAG, "Unable to launch as UID " + launchedFromUid + " package "
120                         + launchedFromPackage + ", while running in "
121                         + ActivityThread.currentProcessName(), e);
122             }
123 
124             if (shouldShowDisclosure) {
125                 Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show();
126             }
127         } else {
128             Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
129                     + callingUserId + " to user " + targetUserId);
130         }
131         finish();
132     }
133 
canForward(Intent intent, int targetUserId)134     boolean canForward(Intent intent, int targetUserId)  {
135         IPackageManager ipm = AppGlobals.getPackageManager();
136         if (intent.getAction().equals(Intent.ACTION_CHOOSER)) {
137             // The EXTRA_INITIAL_INTENTS may not be allowed to be forwarded.
138             if (intent.hasExtra(Intent.EXTRA_INITIAL_INTENTS)) {
139                 Slog.wtf(TAG, "An chooser intent with extra initial intents cannot be forwarded to"
140                         + " a different user");
141                 return false;
142             }
143             if (intent.hasExtra(Intent.EXTRA_REPLACEMENT_EXTRAS)) {
144                 Slog.wtf(TAG, "A chooser intent with replacement extras cannot be forwarded to a"
145                         + " different user");
146                 return false;
147             }
148             intent = (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
149         }
150         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
151         if (intent.getSelector() != null) {
152             intent = intent.getSelector();
153         }
154         try {
155             return ipm.canForwardTo(intent, resolvedType, getUserId(),
156                     targetUserId);
157         } catch (RemoteException e) {
158             Slog.e(TAG, "PackageManagerService is dead?");
159             return false;
160         }
161     }
162 
163     /**
164      * Returns the userId of the managed profile for this device or UserHandle.USER_NULL if there is
165      * no managed profile.
166      *
167      * TODO: Remove the assumption that there is only one managed profile
168      * on the device.
169      */
getManagedProfile()170     private int getManagedProfile() {
171         UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
172         List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
173         for (UserInfo userInfo : relatedUsers) {
174             if (userInfo.isManagedProfile()) return userInfo.id;
175         }
176         Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
177                 + " has been called, but there is no managed profile");
178         return UserHandle.USER_NULL;
179     }
180 }
181