From 05542603dd4f1e0ea47a3dca01de3999a9a329a9 Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Mon, 11 Aug 2014 14:07:27 -0700 Subject: [PATCH] Less intrusive VPN dialog and other UX tweaks. -The ability to launch VPNs is now sticky; once approved by the user, further approvals are not needed UNLESS the connection is revoked in Quick Settings. -The old persistent notification has been removed in favor of the new Quick Settings UI. -The name of the VPN app is now pulled from the label of the VPN service rather than the app itself, if one is set. Bug: 12878887 Bug: 16578022 Change-Id: I102a14c05db26ee3aef030cda971e5165f078a91 --- core/java/android/app/AppOpsManager.java | 39 ++-- .../android/net/IConnectivityManager.aidl | 2 + .../android/internal/net/LegacyVpnInfo.java | 3 - .../com/android/internal/net/VpnConfig.java | 29 ++- packages/SystemUI/res/values/strings.xml | 4 +- .../src/com/android/systemui/qs/QSFooter.java | 8 +- .../statusbar/policy/SecurityController.java | 3 +- .../policy/SecurityControllerImpl.java | 26 +-- packages/VpnDialogs/AndroidManifest.xml | 9 - .../res/drawable-hdpi/ic_vpn_dialog.png | Bin 0 -> 943 bytes .../res/drawable-mdpi/ic_vpn_dialog.png | Bin 0 -> 629 bytes .../res/drawable-xhdpi/ic_vpn_dialog.png | Bin 0 -> 1035 bytes .../res/drawable-xxhdpi/ic_vpn_dialog.png | Bin 0 -> 1257 bytes .../res/drawable-xxxhdpi/ic_vpn_dialog.png | Bin 0 -> 1884 bytes packages/VpnDialogs/res/layout/confirm.xml | 43 +--- packages/VpnDialogs/res/layout/manage.xml | 45 ---- packages/VpnDialogs/res/values/strings.xml | 41 +--- .../com/android/vpndialogs/ConfirmDialog.java | 46 ++-- .../com/android/vpndialogs/ManageDialog.java | 204 ------------------ .../android/server/ConnectivityService.java | 14 ++ .../com/android/server/connectivity/Vpn.java | 173 +++++---------- .../server/net/LockdownVpnTracker.java | 2 - 22 files changed, 174 insertions(+), 517 deletions(-) create mode 100644 packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png create mode 100644 packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png create mode 100644 packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png create mode 100644 packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png create mode 100644 packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png delete mode 100644 packages/VpnDialogs/res/layout/manage.xml delete mode 100644 packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 0d2ad08ef8b80..66928ca2f859a 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -16,25 +16,25 @@ package android.app; -import android.Manifest; +import android.annotation.SystemApi; +import android.app.usage.UsageStatsManager; +import android.content.Context; import android.media.AudioAttributes.AttributeUsage; import android.os.Binder; import android.os.IBinder; -import android.os.UserManager; -import android.util.ArrayMap; - -import com.android.internal.app.IAppOpsService; -import com.android.internal.app.IAppOpsCallback; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import android.content.Context; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; +import android.os.UserManager; +import android.util.ArrayMap; + +import com.android.internal.app.IAppOpsCallback; +import com.android.internal.app.IAppOpsService; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; /** * API for interacting with "application operation" tracking. @@ -203,8 +203,10 @@ public class AppOpsManager { public static final int OP_TOAST_WINDOW = 45; /** @hide Capture the device's display contents and/or audio */ public static final int OP_PROJECT_MEDIA = 46; + /** @hide Activate a VPN connection without user intervention. */ + public static final int OP_ACTIVATE_VPN = 47; /** @hide */ - public static final int _NUM_OP = 47; + public static final int _NUM_OP = 48; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = @@ -218,6 +220,9 @@ public class AppOpsManager { /** Continually monitoring location data with a relatively high power request. */ public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power"; + /** Activate a VPN connection without user intervention. @hide */ + @SystemApi + public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; /** * This maps each operation to the operation that serves as the @@ -275,6 +280,7 @@ public class AppOpsManager { OP_MUTE_MICROPHONE, OP_TOAST_WINDOW, OP_PROJECT_MEDIA, + OP_ACTIVATE_VPN, }; /** @@ -329,6 +335,7 @@ public class AppOpsManager { null, null, null, + OPSTR_ACTIVATE_VPN, }; /** @@ -383,6 +390,7 @@ public class AppOpsManager { "MUTE_MICROPHONE", "TOAST_WINDOW", "PROJECT_MEDIA", + "ACTIVATE_VPN", }; /** @@ -437,6 +445,7 @@ public class AppOpsManager { null, // no permission for muting/unmuting microphone null, // no permission for displaying toasts null, // no permission for projecting media + null, // no permission for activating vpn }; /** @@ -492,6 +501,7 @@ public class AppOpsManager { UserManager.DISALLOW_UNMUTE_MICROPHONE, // MUTE_MICROPHONE UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW null, //PROJECT_MEDIA + UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN }; /** @@ -546,6 +556,7 @@ public class AppOpsManager { false, //MUTE_MICROPHONE true, //TOAST_WINDOW false, //PROJECT_MEDIA + false, //ACTIVATE_VPN }; /** @@ -599,6 +610,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA + AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN }; /** @@ -656,6 +668,7 @@ public class AppOpsManager { false, false, false, + false, }; private static HashMap sOpStrToOp = new HashMap(); diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 0814e0fc4be12..b2fc3be27d993 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -108,6 +108,8 @@ interface IConnectivityManager boolean prepareVpn(String oldPackage, String newPackage); + void setVpnPackageAuthorization(boolean authorized); + ParcelFileDescriptor establishVpn(in VpnConfig config); VpnConfig getVpnConfig(); diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java index d6f6d0bac1a0d..f812ad6ae325f 100644 --- a/core/java/com/android/internal/net/LegacyVpnInfo.java +++ b/core/java/com/android/internal/net/LegacyVpnInfo.java @@ -40,7 +40,6 @@ public class LegacyVpnInfo implements Parcelable { public String key; public int state = -1; - public PendingIntent intent; @Override public int describeContents() { @@ -51,7 +50,6 @@ public class LegacyVpnInfo implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeString(key); out.writeInt(state); - out.writeParcelable(intent, flags); } public static final Parcelable.Creator CREATOR = @@ -61,7 +59,6 @@ public class LegacyVpnInfo implements Parcelable { LegacyVpnInfo info = new LegacyVpnInfo(); info.key = in.readString(); info.state = in.readInt(); - info.intent = in.readParcelable(null); return info; } diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index 009926921659c..aa66d7df464bb 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -20,17 +20,19 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; import android.content.res.Resources; +import android.net.LinkAddress; +import android.net.RouteInfo; import android.os.Parcel; import android.os.Parcelable; -import android.os.UserHandle; -import android.net.RouteInfo; -import android.net.LinkAddress; import java.net.Inet4Address; import java.net.InetAddress; -import java.util.List; import java.util.ArrayList; +import java.util.List; /** * A simple container used to carry information in VpnBuilder, VpnDialogs, @@ -55,12 +57,19 @@ public class VpnConfig implements Parcelable { return intent; } - public static PendingIntent getIntentForStatusPanel(Context context) { - Intent intent = new Intent(); - intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog"); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY | - Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - return PendingIntent.getActivityAsUser(context, 0, intent, 0, null, UserHandle.CURRENT); + public static CharSequence getVpnLabel(Context context, String packageName) + throws NameNotFoundException { + PackageManager pm = context.getPackageManager(); + Intent intent = new Intent(SERVICE_INTERFACE); + intent.setPackage(packageName); + List services = pm.queryIntentServices(intent, 0 /* flags */); + if (services != null && services.size() == 1) { + // This app contains exactly one VPN service. Call loadLabel, which will attempt to + // load the service's label, and fall back to the app label if none is present. + return services.get(0).loadLabel(pm); + } else { + return pm.getApplicationInfo(packageName, 0).loadLabel(pm); + } } public String user; diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index ed3fa58b2fa4b..8f05f7ba895e6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -834,8 +834,8 @@ Network monitoring - - Open app + + Disable VPN Disconnect VPN diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java index bfbc56c4a9344..a8199fa35a972 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java @@ -119,11 +119,7 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_NEGATIVE) { - if (mSecurityController.isLegacyVpn()) { - mSecurityController.disconnectFromLegacyVpn(); - } else { - mSecurityController.openVpnApp(); - } + mSecurityController.disconnectFromVpn(); } } @@ -142,7 +138,7 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene if (mSecurityController.isLegacyVpn()) { return mContext.getString(R.string.disconnect_vpn); } else { - return mContext.getString(R.string.open_app); + return mContext.getString(R.string.disable_vpn); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java index ede8129ecd9ac..3a5a53b5d42a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java @@ -23,8 +23,7 @@ public interface SecurityController { String getVpnApp(); boolean isLegacyVpn(); String getLegacyVpnName(); - void openVpnApp(); - void disconnectFromLegacyVpn(); + void disconnectFromVpn(); void addCallback(VpnCallback callback); void removeCallback(VpnCallback callback); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index 8e04e5e7ff19d..ae0291bee7019 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.policy; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; @@ -109,18 +108,17 @@ public class SecurityControllerImpl implements SecurityController { } @Override - public void openVpnApp() { - Intent i = mContext.getPackageManager().getLaunchIntentForPackage(mVpnConfig.user); - if (i != null) { - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(i); - } - } - - @Override - public void disconnectFromLegacyVpn() { + public void disconnectFromVpn() { try { - mConnectivityService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); + if (isLegacyVpn()) { + mConnectivityService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); + } else { + // Prevent this app from initiating VPN connections in the future without user + // intervention. + mConnectivityService.setVpnPackageAuthorization(false); + + mConnectivityService.prepareVpn(mVpnConfig.user, VpnConfig.LEGACY_VPN); + } } catch (Exception e) { Log.e(TAG, "Unable to disconnect from VPN", e); } @@ -154,9 +152,7 @@ public class SecurityControllerImpl implements SecurityController { mIsVpnEnabled = mVpnConfig != null; if (mVpnConfig != null && !mVpnConfig.legacy) { - ApplicationInfo info = - mContext.getPackageManager().getApplicationInfo(mVpnConfig.user, 0); - mVpnName = mContext.getPackageManager().getApplicationLabel(info).toString(); + mVpnName = VpnConfig.getVpnLabel(mContext, mVpnConfig.user).toString(); } } catch (RemoteException | NameNotFoundException e) { Log.w(TAG, "Unable to get current VPN", e); diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml index 03d920a4b71b8..1768400862a6b 100644 --- a/packages/VpnDialogs/AndroidManifest.xml +++ b/packages/VpnDialogs/AndroidManifest.xml @@ -28,14 +28,5 @@ - - - - - - - diff --git a/packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..a0b4b6131a7818a0d9e7a967266c05a3983bceae GIT binary patch literal 943 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9>jA5L~c#`DCC7XMsm#F_88EW4Dvpb_@(m^`0({ArXh)PT!p;94OGXe=BcTz!Vp! zDVhSRx>G^|8Z{O)F;y_SNM@{1o+9Vs&A5=$qob>70{a7AkIB;x8E*fvZP|_b4;6d( zW>0;a;nuD?C+SbH*g;?`XGFR-Hvg612gN?bIiKjYK&$L+vd#JoG9^sf?VFc zGZV8IZWmcFR5`@oU-@g_59XJ96GMWHxmPXww{%Vkv(d`zdDpLgFFw0{me%Ee6GcDx zO1^Iw;f+yfn>2m)zutuPC98xa?=Y`Bu~1UhYu+T$FPkoy*!lhEE|9f2dy?CR@gIY1 za!ksm3f|7x2Syu~{VSgETVz|~HO|}RXYUs<7U>_zKle?PqvutQ?;nYfn1G9Er9ZA% zN0w_k9b+up(zPtbx3|1$-oZGv1%_DxeW!BX@39nilyqWGob)kY+g0|YmDGK%sfXZ1Kbg$#=@qzftXnmA>RaEJU!3-9{=ym8+JWc#f zK-KL7$|pacThwvJTaf!KC0oA6IT)o&&~Jg;aR#y*d6 zeIxsUP&fW9@dwPi>@W1BTd&ZaU%RR4Jgtc)#zTq^^Eowb2}C>nC}Q!>*kacelC@bVK-gCxj?;QX|b o^2DN42FH~Aq*MjZ+{EFVdQ&MBb@01%>q=Kufz literal 0 HcmV?d00001 diff --git a/packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..df5dfe8e1a6a519db02c040a0dc70ff482354264 GIT binary patch literal 629 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ueoXKL{?^yL>WGgtNdSvKUBvfU(=jY&)RwuAVNAAs)xyPC4y&*g(M5e?fPXLoJ7y zhwD@R+r0a))+a>9$zN~{*J1eD=)j?5nl{n;VA16XOH!{-T$gkHag|N7^tVl|E{D!} zN;4MDTPL*eWaBZHU&3qc8N_d7=a=yCG#Y-;>1k}tsZ&~dlu57AJ$3h`7w6?0=GE~3 zd>bfeWXbf-RfM}!fcgHWyG&>2eEO%!EGRLN*^V{(xYYX6SH=s18@A0q;_G0RHhPZ`M0(pBStszUK6mTdbeA&dBxJ z!r`}7sn%Nf>!PyB=Np5k7QFna+o*l1eb(NYY6b3Fv$GE7&OKr_qk5+MzU2Na{8E`w@XHhpLFYX!{UG2-&ajOd-Z{) z@aE|ubqwdDXIfacH-rE~R<*=6q9i4;B-JXpC>2OC7#SFv=o*;o8d!!H8e5r~SQ%Ra zxmE@SJ8J{|P&DM`r(~v8;?{6N;pHcw21$?&!TD(=<%vb942~)JNvR5+xryniL8*x; Um4zo$LDA3P>FVdQ&MBb@0APja&j0`b literal 0 HcmV?d00001 diff --git a/packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..18d5a3aeddeeb150ad1c23d3c48bcc3c13da0207 GIT binary patch literal 1035 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 A#Q*>R literal 0 HcmV?d00001 diff --git a/packages/VpnDialogs/res/layout/confirm.xml b/packages/VpnDialogs/res/layout/confirm.xml index ee7f4b84e400b..66fec5966f3ea 100644 --- a/packages/VpnDialogs/res/layout/confirm.xml +++ b/packages/VpnDialogs/res/layout/confirm.xml @@ -18,41 +18,12 @@ - - - - - - - - - - - - - + android:textSize="18sp" + android:paddingTop="4mm" + android:paddingLeft="3mm" + android:paddingRight="3mm" + android:paddingBottom="4mm"/> diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml deleted file mode 100644 index 56332c3bebeb6..0000000000000 --- a/packages/VpnDialogs/res/layout/manage.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml index 3ff767ac7f9ff..84206a164ec8e 100644 --- a/packages/VpnDialogs/res/values/strings.xml +++ b/packages/VpnDialogs/res/values/strings.xml @@ -17,40 +17,15 @@ - %s - attempts to create a VPN connection. - + Connection request - By proceeding, you are giving the application - permission to intercept all network traffic. - Do NOT accept unless you trust the application. Otherwise, - you run the risk of having your data compromised by a malicious - software. - - - - I trust this application. - - - VPN is connected - - Configure - - Disconnect - - - Session: - - Duration: - - Sent: - - Received: - - - - %1$s bytes / - %2$s packets + %s wants to set up a VPN connection + that allows it to monitor network traffic. Only accept if you trust the source. + +
+ + ]]> appears at the top of your screen when VPN is active.
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java index ddafc66561017..897c96cf50382 100644 --- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java +++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java @@ -18,21 +18,28 @@ package com.android.vpndialogs; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; import android.net.IConnectivityManager; +import android.net.VpnService; import android.os.ServiceManager; +import android.text.Html; +import android.text.Html.ImageGetter; import android.util.Log; import android.view.View; import android.widget.Button; -import android.widget.CompoundButton; -import android.widget.ImageView; import android.widget.TextView; import com.android.internal.app.AlertActivity; +import com.android.internal.net.VpnConfig; -public class ConfirmDialog extends AlertActivity implements - CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener { +import java.util.List; + +public class ConfirmDialog extends AlertActivity + implements DialogInterface.OnClickListener, ImageGetter { private static final String TAG = "VpnConfirm"; private String mPackage; @@ -56,27 +63,22 @@ public class ConfirmDialog extends AlertActivity implements return; } - PackageManager pm = getPackageManager(); - ApplicationInfo app = pm.getApplicationInfo(mPackage, 0); - View view = View.inflate(this, R.layout.confirm, null); - ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(app.loadIcon(pm)); - ((TextView) view.findViewById(R.id.prompt)).setText( - getString(R.string.prompt, app.loadLabel(pm))); - ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this); - mAlertParams.mIconAttrId = android.R.attr.alertDialogIcon; - mAlertParams.mTitle = getText(android.R.string.dialog_alert_title); + ((TextView) view.findViewById(R.id.warning)).setText( + Html.fromHtml( + getString(R.string.warning, VpnConfig.getVpnLabel(this, mPackage)), + this, null /* tagHandler */)); + + mAlertParams.mTitle = getText(R.string.prompt); mAlertParams.mPositiveButtonText = getText(android.R.string.ok); mAlertParams.mPositiveButtonListener = this; mAlertParams.mNegativeButtonText = getText(android.R.string.cancel); - mAlertParams.mNegativeButtonListener = this; mAlertParams.mView = view; setupAlert(); getWindow().setCloseOnTouchOutside(false); mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); - mButton.setEnabled(false); mButton.setFilterTouchesWhenObscured(true); } catch (Exception e) { Log.e(TAG, "onResume", e); @@ -85,18 +87,24 @@ public class ConfirmDialog extends AlertActivity implements } @Override - public void onBackPressed() { + public Drawable getDrawable(String source) { + // Should only reach this when fetching the VPN icon for the warning string. + Drawable icon = getDrawable(R.drawable.ic_vpn_dialog); + icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); + return icon; } @Override - public void onCheckedChanged(CompoundButton button, boolean checked) { - mButton.setEnabled(checked); + public void onBackPressed() { } @Override public void onClick(DialogInterface dialog, int which) { try { - if (which == DialogInterface.BUTTON_POSITIVE && mService.prepareVpn(null, mPackage)) { + if (mService.prepareVpn(null, mPackage)) { + // Authorize this app to initiate VPN connections in the future without user + // intervention. + mService.setVpnPackageAuthorization(true); setResult(RESULT_OK); } } catch (Exception e) { diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java deleted file mode 100644 index eb20995ade107..0000000000000 --- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.vpndialogs; - -import android.content.Context; -import android.content.DialogInterface; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.net.IConnectivityManager; -import android.os.Handler; -import android.os.Message; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.util.Log; -import android.view.View; -import android.widget.TextView; - -import com.android.internal.app.AlertActivity; -import com.android.internal.net.VpnConfig; - -import java.io.DataInputStream; -import java.io.FileInputStream; - -public class ManageDialog extends AlertActivity implements - DialogInterface.OnClickListener, Handler.Callback { - private static final String TAG = "VpnManage"; - - private VpnConfig mConfig; - - private IConnectivityManager mService; - - private TextView mDuration; - private TextView mDataTransmitted; - private TextView mDataReceived; - private boolean mDataRowsHidden; - - private Handler mHandler; - - @Override - protected void onResume() { - super.onResume(); - - if (getCallingPackage() != null) { - Log.e(TAG, getCallingPackage() + " cannot start this activity"); - finish(); - return; - } - - try { - - mService = IConnectivityManager.Stub.asInterface( - ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); - - mConfig = mService.getVpnConfig(); - - // mConfig can be null if we are a restricted user, in that case don't show this dialog - if (mConfig == null) { - finish(); - return; - } - - View view = View.inflate(this, R.layout.manage, null); - if (mConfig.session != null) { - ((TextView) view.findViewById(R.id.session)).setText(mConfig.session); - } - mDuration = (TextView) view.findViewById(R.id.duration); - mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted); - mDataReceived = (TextView) view.findViewById(R.id.data_received); - mDataRowsHidden = true; - - if (mConfig.legacy) { - mAlertParams.mIconId = android.R.drawable.ic_dialog_info; - mAlertParams.mTitle = getText(R.string.legacy_title); - } else { - PackageManager pm = getPackageManager(); - ApplicationInfo app = pm.getApplicationInfo(mConfig.user, 0); - mAlertParams.mIcon = app.loadIcon(pm); - mAlertParams.mTitle = app.loadLabel(pm); - } - if (mConfig.configureIntent != null) { - mAlertParams.mPositiveButtonText = getText(R.string.configure); - mAlertParams.mPositiveButtonListener = this; - } - mAlertParams.mNeutralButtonText = getText(R.string.disconnect); - mAlertParams.mNeutralButtonListener = this; - mAlertParams.mNegativeButtonText = getText(android.R.string.cancel); - mAlertParams.mNegativeButtonListener = this; - mAlertParams.mView = view; - setupAlert(); - - if (mHandler == null) { - mHandler = new Handler(this); - } - mHandler.sendEmptyMessage(0); - } catch (Exception e) { - Log.e(TAG, "onResume", e); - finish(); - } - } - - @Override - protected void onPause() { - super.onPause(); - if (!isFinishing()) { - finish(); - } - } - - @Override - public void onClick(DialogInterface dialog, int which) { - try { - if (which == DialogInterface.BUTTON_POSITIVE) { - mConfig.configureIntent.send(); - } else if (which == DialogInterface.BUTTON_NEUTRAL) { - if (mConfig.legacy) { - mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); - } else { - mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN); - } - } - } catch (Exception e) { - Log.e(TAG, "onClick", e); - finish(); - } - } - - @Override - public boolean handleMessage(Message message) { - mHandler.removeMessages(0); - - if (!isFinishing()) { - if (mConfig.startTime != -1) { - long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000; - mDuration.setText(String.format("%02d:%02d:%02d", - seconds / 3600, seconds / 60 % 60, seconds % 60)); - } - - String[] numbers = getNumbers(); - if (numbers != null) { - // First unhide the related data rows. - if (mDataRowsHidden) { - findViewById(R.id.data_transmitted_row).setVisibility(View.VISIBLE); - findViewById(R.id.data_received_row).setVisibility(View.VISIBLE); - mDataRowsHidden = false; - } - - // [1] and [2] are received data in bytes and packets. - mDataReceived.setText(getString(R.string.data_value_format, - numbers[1], numbers[2])); - - // [9] and [10] are transmitted data in bytes and packets. - mDataTransmitted.setText(getString(R.string.data_value_format, - numbers[9], numbers[10])); - } - mHandler.sendEmptyMessageDelayed(0, 1000); - } - return true; - } - - private String[] getNumbers() { - DataInputStream in = null; - try { - // See dev_seq_printf_stats() in net/core/dev.c. - in = new DataInputStream(new FileInputStream("/proc/net/dev")); - String prefix = mConfig.interfaze + ':'; - - while (true) { - String line = in.readLine().trim(); - if (line.startsWith(prefix)) { - String[] numbers = line.substring(prefix.length()).split(" +"); - for (int i = 1; i < 17; ++i) { - if (!numbers[i].equals("0")) { - return numbers; - } - } - break; - } - } - } catch (Exception e) { - // ignore - } finally { - try { - in.close(); - } catch (Exception e) { - // ignore - } - } - return null; - } -} diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 67c01e50bbe37..1d3daab2284d0 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2662,6 +2662,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * Set whether the current VPN package has the ability to launch VPNs without + * user intervention. This method is used by system UIs and not available + * in ConnectivityManager. Permissions are checked in Vpn class. + * @hide + */ + @Override + public void setVpnPackageAuthorization(boolean authorized) { + int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized(mVpns) { + mVpns.get(user).setPackageAuthorization(authorized); + } + } + /** * Configure a TUN interface and return its file descriptor. Parameters * are encoded and opaque to this class. This method is used by VpnBuilder diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 0f6b3adc609b2..8466860a58a1b 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -21,9 +21,7 @@ import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import android.app.AppGlobals; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; +import android.app.AppOpsManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -35,10 +33,6 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.net.BaseNetworkStateTracker; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; @@ -51,7 +45,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; -import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.UidRange; import android.os.Binder; @@ -70,15 +63,15 @@ import android.os.UserManager; import android.security.Credentials; import android.security.KeyStore; import android.util.Log; -import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.R; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.server.net.BaseNetworkObserver; +import libcore.io.IoUtils; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -92,8 +85,6 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import libcore.io.IoUtils; - /** * @hide */ @@ -114,8 +105,6 @@ public class Vpn { private boolean mAllowIPv6; private Connection mConnection; private LegacyVpnRunner mLegacyVpnRunner; - private PendingIntent mStatusIntent; - private volatile boolean mEnableNotif = true; private volatile boolean mEnableTeardown = true; private final IConnectivityManager mConnService; private final INetworkManagementService mNetd; @@ -179,14 +168,6 @@ public class Vpn { mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); } - /** - * Set if this object is responsible for showing its own notifications. When - * {@code false}, notifications are handled externally by someone else. - */ - public void setEnableNotifications(boolean enableNotif) { - mEnableNotif = enableNotif; - } - /** * Set if this object is responsible for watching for {@link NetworkInfo} * teardown. When {@code false}, teardown is handled externally by someone @@ -228,6 +209,20 @@ public class Vpn { public synchronized boolean prepare(String oldPackage, String newPackage) { // Return false if the package does not match. if (oldPackage != null && !oldPackage.equals(mPackage)) { + // The package doesn't match. If this VPN was not previously authorized, return false + // to force user authorization. Otherwise, revoke the VPN anyway. + if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) { + long token = Binder.clearCallingIdentity(); + try { + // This looks bizarre, but it is what ConfirmDialog in VpnDialogs is doing when + // the user clicks through to allow the VPN to consent. So we are emulating the + // action of the dialog without actually showing it. + prepare(null, oldPackage); + } finally { + Binder.restoreCallingIdentity(token); + } + return true; + } return false; } @@ -240,11 +235,8 @@ public class Vpn { // Check if the caller is authorized. enforceControlPermission(); - // Reset the interface and hide the notification. + // Reset the interface. if (mInterface != null) { - for (UidRange uidRange : mVpnUsers) { - hideNotification(uidRange.getStartUser()); - } agentDisconnect(); jniReset(mInterface); mInterface = null; @@ -287,12 +279,46 @@ public class Vpn { Binder.restoreCallingIdentity(token); } mConfig = null; + updateState(DetailedState.IDLE, "prepare"); return true; } + /** + * Set whether the current package has the ability to launch VPNs without user intervention. + */ + public void setPackageAuthorization(boolean authorized) { + // Check if the caller is authorized. + enforceControlPermission(); + + if (mPackage == null || VpnConfig.LEGACY_VPN.equals(mPackage)) { + return; + } + + long token = Binder.clearCallingIdentity(); + try { + AppOpsManager appOps = + (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, mOwnerUID, mPackage, + authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); + } catch (Exception e) { + Log.wtf(TAG, "Failed to set app ops for package " + mPackage, e); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private boolean isVpnUserPreConsented(String packageName) { + AppOpsManager appOps = + (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + + // Verify that the caller matches the given package and has permission to activate VPNs. + return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(), + packageName) == AppOpsManager.MODE_ALLOWED; + } + private int getAppUid(String app) { - if (app == VpnConfig.LEGACY_VPN) { + if (VpnConfig.LEGACY_VPN.equals(app)) { return Process.myUid(); } PackageManager pm = mContext.getPackageManager(); @@ -355,9 +381,10 @@ public class Vpn { try { mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE, mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) { + @Override public void unwanted() { // We are user controlled, not driven by NetworkRequest. - }; + } }; } finally { Binder.restoreCallingIdentity(token); @@ -540,39 +567,6 @@ public class Vpn { // add the user mVpnUsers.add(UidRange.createForUser(user)); - - // show the notification - if (!mPackage.equals(VpnConfig.LEGACY_VPN)) { - // Load everything for the user's notification - PackageManager pm = mContext.getPackageManager(); - ApplicationInfo app = null; - final long token = Binder.clearCallingIdentity(); - try { - app = AppGlobals.getPackageManager().getApplicationInfo(mPackage, 0, mUserId); - } catch (RemoteException e) { - throw new IllegalStateException("Invalid application"); - } finally { - Binder.restoreCallingIdentity(token); - } - String label = app.loadLabel(pm).toString(); - // Load the icon and convert it into a bitmap. - Drawable icon = app.loadIcon(pm); - Bitmap bitmap = null; - if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) { - int width = mContext.getResources().getDimensionPixelSize( - android.R.dimen.notification_large_icon_width); - int height = mContext.getResources().getDimensionPixelSize( - android.R.dimen.notification_large_icon_height); - icon.setBounds(0, 0, width, height); - bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(bitmap); - icon.draw(c); - c.setBitmap(null); - } - showNotification(label, bitmap, user); - } else { - showNotification(null, null, user); - } } private void removeVpnUserLocked(int user) { @@ -584,7 +578,6 @@ public class Vpn { mNetworkAgent.removeUidRanges(new UidRange[] { uidRange }); } mVpnUsers.remove(uidRange); - hideNotification(user); } private void onUserAdded(int userId) { @@ -652,9 +645,6 @@ public class Vpn { public void interfaceRemoved(String interfaze) { synchronized (Vpn.this) { if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { - for (UidRange uidRange : mVpnUsers) { - hideNotification(uidRange.getStartUser()); - } mVpnUsers = null; mInterface = null; if (mConnection != null) { @@ -712,56 +702,6 @@ public class Vpn { } } - private void showNotification(String label, Bitmap icon, int user) { - if (!mEnableNotif) return; - final long token = Binder.clearCallingIdentity(); - try { - mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext); - - NotificationManager nm = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); - - if (nm != null) { - String title = (label == null) ? mContext.getString(R.string.vpn_title) : - mContext.getString(R.string.vpn_title_long, label); - String text = (mConfig.session == null) ? mContext.getString(R.string.vpn_text) : - mContext.getString(R.string.vpn_text_long, mConfig.session); - - Notification notification = new Notification.Builder(mContext) - .setSmallIcon(R.drawable.vpn_connected) - .setLargeIcon(icon) - .setContentTitle(title) - .setContentText(text) - .setContentIntent(mStatusIntent) - .setDefaults(0) - .setOngoing(true) - .setColor(mContext.getResources().getColor( - com.android.internal.R.color.system_notification_accent_color)) - .build(); - nm.notifyAsUser(null, R.drawable.vpn_connected, notification, new UserHandle(user)); - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private void hideNotification(int user) { - if (!mEnableNotif) return; - mStatusIntent = null; - - NotificationManager nm = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); - - if (nm != null) { - final long token = Binder.clearCallingIdentity(); - try { - nm.cancelAsUser(null, R.drawable.vpn_connected, new UserHandle(user)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - } - public synchronized boolean addAddress(String address, int prefixLength) { if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) { return false; @@ -971,9 +911,6 @@ public class Vpn { final LegacyVpnInfo info = new LegacyVpnInfo(); info.key = mConfig.user; info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo); - if (mNetworkInfo.isConnected()) { - info.intent = mStatusIntent; - } return info; } diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java index 52e741ba75511..04df3e7eec203 100644 --- a/services/core/java/com/android/server/net/LockdownVpnTracker.java +++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java @@ -205,7 +205,6 @@ public class LockdownVpnTracker { private void initLocked() { Slog.d(TAG, "initLocked()"); - mVpn.setEnableNotifications(false); mVpn.setEnableTeardown(false); final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET); @@ -249,7 +248,6 @@ public class LockdownVpnTracker { hideNotification(); mContext.unregisterReceiver(mResetReceiver); - mVpn.setEnableNotifications(true); mVpn.setEnableTeardown(true); }