110fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot/*
210fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * Copyright (C) 2014 The Android Open Source Project
310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot *
410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * Licensed under the Apache License, Version 2.0 (the "License");
510fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * you may not use this file except in compliance with the License.
610fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * You may obtain a copy of the License at
710fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot *
810fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot *      http://www.apache.org/licenses/LICENSE-2.0
910fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot *
1010fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * Unless required by applicable law or agreed to in writing, software
1110fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * distributed under the License is distributed on an "AS IS" BASIS,
1210fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * See the License for the specific language governing permissions and
1410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot * limitations under the License.
1510fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot */
1610fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
1710fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotpackage com.android.internal.app;
1810fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
193ea4310a2245763de1ba29b8ce0a21e99a702746Robin Leeimport static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
203ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee
2110fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.app.Activity;
223ea4310a2245763de1ba29b8ce0a21e99a702746Robin Leeimport android.app.ActivityManagerNative;
239797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkeyimport android.app.ActivityThread;
2410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.app.AppGlobals;
259797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkeyimport android.app.admin.DevicePolicyManager;
2610fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.content.Context;
2710fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.content.Intent;
2810fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.content.pm.IPackageManager;
2910fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.content.pm.UserInfo;
309797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkeyimport android.os.Bundle;
313ea4310a2245763de1ba29b8ce0a21e99a702746Robin Leeimport android.os.RemoteException;
3210fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.os.UserHandle;
3310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.os.UserManager;
3410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport android.util.Slog;
353ea4310a2245763de1ba29b8ce0a21e99a702746Robin Leeimport android.widget.Toast;
369797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey
3710fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotimport java.util.List;
3810fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
399797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey/**
409797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey * This is used in conjunction with
419797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey * {@link DevicePolicyManager#addCrossProfileIntentFilter} to enable intents to
429797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey * be passed in and out of a managed profile.
4310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot */
4410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevotpublic class IntentForwarderActivity extends Activity  {
4510fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
4610fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot    public static String TAG = "IntentForwarderActivity";
4710fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
48741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot    public static String FORWARD_INTENT_TO_PARENT
49741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot            = "com.android.internal.app.ForwardIntentToParent";
5010fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
5110fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot    public static String FORWARD_INTENT_TO_MANAGED_PROFILE
5210fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot            = "com.android.internal.app.ForwardIntentToManagedProfile";
5310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
5410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot    @Override
5510fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot    protected void onCreate(Bundle savedInstanceState) {
5610fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        super.onCreate(savedInstanceState);
5710fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        Intent intentReceived = getIntent();
5810fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
5910fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        String className = intentReceived.getComponent().getClassName();
600e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        final int targetUserId;
613ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee        final int userMessageId;
6210fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
63741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot        if (className.equals(FORWARD_INTENT_TO_PARENT)) {
643ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee            userMessageId = com.android.internal.R.string.forward_intent_to_owner;
65741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot            targetUserId = getProfileParent();
6610fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
673ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee            userMessageId = com.android.internal.R.string.forward_intent_to_work;
680e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            targetUserId = getManagedProfile();
6910fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        } else {
7010fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot            Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
713ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee            userMessageId = -1;
720e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            targetUserId = UserHandle.USER_NULL;
7310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        }
740e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        if (targetUserId == UserHandle.USER_NULL) {
75741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot            // This covers the case where there is no parent / managed profile.
7610fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot            finish();
7710fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot            return;
7810fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        }
7910fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        Intent newIntent = new Intent(intentReceived);
8010fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        newIntent.setComponent(null);
81376e4ba96222163be1f1cf409dc697550be4a285Nicolas Prevot        // Apps should not be allowed to target a specific package in the target user.
82376e4ba96222163be1f1cf409dc697550be4a285Nicolas Prevot        newIntent.setPackage(null);
8310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
8410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot                |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
8510fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        int callingUserId = getUserId();
860e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot
870e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        if (canForward(newIntent, targetUserId)) {
88decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot            if (Intent.ACTION_CHOOSER.equals(newIntent.getAction())) {
890e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                Intent innerIntent = (Intent) newIntent.getParcelableExtra(Intent.EXTRA_INTENT);
90decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot                // At this point, innerIntent is not null. Otherwise, canForward would have returned
91decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot                // false.
92107f7b7becdb5fe6d735a4f1355eb3421f068fb0Nicolas Prevot                innerIntent.prepareToLeaveUser(callingUserId);
930e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            } else {
94107f7b7becdb5fe6d735a4f1355eb3421f068fb0Nicolas Prevot                newIntent.prepareToLeaveUser(callingUserId);
950e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            }
963ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee
973ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee            final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser(
980e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                        newIntent, MATCH_DEFAULT_ONLY, targetUserId);
993ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee
1002b43c73e66d99a5ccc8a23fd1c4e2028f9dd05f2Kenny Guy            // Don't show the disclosure if next activity is ResolverActivity or ChooserActivity
1012b43c73e66d99a5ccc8a23fd1c4e2028f9dd05f2Kenny Guy            // as those will already have shown work / personal as neccesary etc.
1022b43c73e66d99a5ccc8a23fd1c4e2028f9dd05f2Kenny Guy            final boolean shouldShowDisclosure = ri == null || ri.activityInfo == null ||
1032b43c73e66d99a5ccc8a23fd1c4e2028f9dd05f2Kenny Guy                    !"android".equals(ri.activityInfo.packageName) ||
1042b43c73e66d99a5ccc8a23fd1c4e2028f9dd05f2Kenny Guy                    !(ResolverActivity.class.getName().equals(ri.activityInfo.name)
105e7c74cc96eeecec52401d9bf720234d1421cfebcAdam Powell                    || ChooserActivity.class.getName().equals(ri.activityInfo.name));
1063ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee
1079797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey            try {
108a7cfbe0e548ac76f20915b65851b8bc9095aa541Dianne Hackborn                startActivityAsCaller(newIntent, null, false, targetUserId);
1099797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey            } catch (RuntimeException e) {
1109797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                int launchedFromUid = -1;
1119797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                String launchedFromPackage = "?";
1129797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                try {
1139797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                    launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
1149797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                            getActivityToken());
1159797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                    launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
1169797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                            getActivityToken());
1179797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                } catch (RemoteException ignored) {
1189797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                }
1199797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey
1209797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                Slog.wtf(TAG, "Unable to launch as UID " + launchedFromUid + " package "
1219797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                        + launchedFromPackage + ", while running in "
1229797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey                        + ActivityThread.currentProcessName(), e);
1239797880808320e3a7bae1f59bc7e0c5a13189e5fJeff Sharkey            }
1243ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee
1253ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee            if (shouldShowDisclosure) {
1263ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee                Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show();
1273ea4310a2245763de1ba29b8ce0a21e99a702746Robin Lee            }
12810fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        } else {
129decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot            Slog.wtf(TAG, "the intent: " + newIntent + " cannot be forwarded from user "
1300e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                    + callingUserId + " to user " + targetUserId);
13110fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        }
13210fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        finish();
13310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot    }
13410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot
1350e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot    boolean canForward(Intent intent, int targetUserId)  {
1360e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        IPackageManager ipm = AppGlobals.getPackageManager();
137decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot        if (Intent.ACTION_CHOOSER.equals(intent.getAction())) {
1380e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            // The EXTRA_INITIAL_INTENTS may not be allowed to be forwarded.
1390e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            if (intent.hasExtra(Intent.EXTRA_INITIAL_INTENTS)) {
1400e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                Slog.wtf(TAG, "An chooser intent with extra initial intents cannot be forwarded to"
1410e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                        + " a different user");
1420e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                return false;
1430e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            }
1440e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            if (intent.hasExtra(Intent.EXTRA_REPLACEMENT_EXTRAS)) {
1450e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                Slog.wtf(TAG, "A chooser intent with replacement extras cannot be forwarded to a"
1460e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                        + " different user");
1470e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                return false;
1480e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            }
1490e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            intent = (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
150decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot            if (intent == null) {
151decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot                Slog.wtf(TAG, "Cannot forward a chooser intent with no extra "
152decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot                        + Intent.EXTRA_INTENT);
153decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot                return false;
154decd9ea263d00087f6f90182fc0325953e50cfa4Nicolas Prevot            }
1550e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        }
1560e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
1570e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        if (intent.getSelector() != null) {
1580e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            intent = intent.getSelector();
1590e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        }
1600e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        try {
1610e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            return ipm.canForwardTo(intent, resolvedType, getUserId(),
1620e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot                    targetUserId);
1630e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        } catch (RemoteException e) {
1640e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            Slog.e(TAG, "PackageManagerService is dead?");
1650e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            return false;
1660e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        }
1670e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot    }
1680e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot
16910fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot    /**
1700e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot     * Returns the userId of the managed profile for this device or UserHandle.USER_NULL if there is
1710e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot     * no managed profile.
17210fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot     *
17310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot     * TODO: Remove the assumption that there is only one managed profile
17410fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot     * on the device.
17510fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot     */
1760e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot    private int getManagedProfile() {
17710fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
178741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot        List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.myUserId());
17910fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        for (UserInfo userInfo : relatedUsers) {
1800e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot            if (userInfo.isManagedProfile()) return userInfo.id;
18110fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        }
18210fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot        Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
18310fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot                + " has been called, but there is no managed profile");
1840e2b73f6858479ca963bd53c49f8955d98f14869Nicolas Prevot        return UserHandle.USER_NULL;
18510fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot    }
186741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot
187741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot    /**
188741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot     * Returns the userId of the profile parent or UserHandle.USER_NULL if there is
189741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot     * no parent.
190741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot     */
191741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot    private int getProfileParent() {
192741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
193741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot        UserInfo parent = userManager.getProfileParent(UserHandle.myUserId());
194741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot        if (parent == null) {
195741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot            Slog.wtf(TAG, FORWARD_INTENT_TO_PARENT
196741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot                    + " has been called, but there is no parent");
197741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot            return UserHandle.USER_NULL;
198741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot        }
199741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot        return parent.id;
200741abfc12074623d24297ebb67d98cb2d9126addNicolas Prevot    }
20110fa67c77e11699391e27975fc2d276a0b8c7cbbNicolas Prevot}
202