1
+ /*
2
+ * Copyright (C) 2016 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 .afwsamples .testdpc .profilepolicy .apprestrictions ;
18
+
19
+ import android .app .admin .DevicePolicyManager ;
20
+ import android .content .ComponentName ;
21
+ import android .content .Context ;
22
+ import android .content .pm .PackageInfo ;
23
+ import android .content .pm .PackageManager ;
24
+ import android .content .pm .PackageManager .NameNotFoundException ;
25
+ import android .content .pm .Signature ;
26
+ import android .os .Bundle ;
27
+ import android .os .Handler ;
28
+ import android .os .Message ;
29
+ import android .os .RemoteException ;
30
+ import android .preference .PreferenceManager ;
31
+ import android .util .Log ;
32
+
33
+ import java .util .ArrayList ;
34
+ import java .util .HashSet ;
35
+ import java .util .List ;
36
+ import java .util .Set ;
37
+
38
+ /**
39
+ * Handles the message passed from another package to set the application restrictions.
40
+ *
41
+ * The package name must be provided, along with the application restrictions bundle to set.
42
+ * To clear the application restrictions, an empty bundle should be passed.
43
+ */
44
+ public class AppRestrictionsProxyHandler extends Handler {
45
+
46
+ private static final String TAG = "AppRestrictionsProxy" ;
47
+ private static final int MSG_SET_APPLICATION_RESTRICTIONS = 1 ;
48
+ private static final int MSG_CAN_SET_APPLICATION_RESTRICTIONS = 2 ;
49
+ private static final int MSG_GET_APPLICATION_RESTRICTIONS = 3 ;
50
+
51
+ private static final String APPLICATION_RESTRICTIONS_MANAGING_PACKAGE_SIGNATURES_KEY =
52
+ "application_restrictions_managing_package_signatures" ;
53
+ private static final String APPLICATION_RESTRICTIONS_MANAGING_PACKAGE_KEY =
54
+ "application_restrictions_managing_package" ;
55
+
56
+ public static final String KEY_APPLICATION_RESTRICTIONS = "applicationRestrictions" ;
57
+ public static final String KEY_PACKAGE_NAME = "packageName" ;
58
+ public static final String KEY_CAN_SET_APPLICATION_RESTRICTIONS
59
+ = "canSetApplicationRestrictions" ;
60
+
61
+ private final Context mContext ;
62
+ private final ComponentName mAdmin ;
63
+
64
+ public AppRestrictionsProxyHandler (Context context , ComponentName admin ) {
65
+ mContext = context ;
66
+ mAdmin = admin ;
67
+ }
68
+
69
+ @ Override
70
+ public void handleMessage (Message msg ) {
71
+ switch (msg .what ) {
72
+ case MSG_SET_APPLICATION_RESTRICTIONS : {
73
+ ensureCallerSignature (msg .sendingUid );
74
+ String packageName = msg .getData ().getString (KEY_PACKAGE_NAME );
75
+ Bundle appRestrictions = msg .getData ().getBundle (KEY_APPLICATION_RESTRICTIONS );
76
+ setApplicationRestrictions (packageName , appRestrictions );
77
+ break ;
78
+ }
79
+ case MSG_CAN_SET_APPLICATION_RESTRICTIONS : {
80
+ String callingPackage = mContext .getPackageManager ().getNameForUid (msg .sendingUid );
81
+ String managingPackage = getApplicationRestrictionsManagingPackage ();
82
+ Bundle responseBundle = new Bundle ();
83
+ responseBundle .putBoolean (KEY_CAN_SET_APPLICATION_RESTRICTIONS ,
84
+ callingPackage != null && callingPackage .equals (managingPackage ));
85
+ Message response = Message .obtain ();
86
+ response .setData (responseBundle );
87
+ try {
88
+ msg .replyTo .send (response );
89
+ } catch (RemoteException e ) {
90
+ Log .e (TAG , "Unable to respond to canSetApplicationRestrictions." , e );
91
+ }
92
+ break ;
93
+ }
94
+ case MSG_GET_APPLICATION_RESTRICTIONS : {
95
+ ensureCallerSignature (msg .sendingUid );
96
+ String packageName = msg .getData ().getString (KEY_PACKAGE_NAME );
97
+ Bundle appRestrictions = getApplicationRestrictions (packageName );
98
+ Bundle responseBundle = new Bundle ();
99
+ responseBundle .putBundle (KEY_APPLICATION_RESTRICTIONS , appRestrictions );
100
+ Message response = Message .obtain ();
101
+ response .setData (responseBundle );
102
+ try {
103
+ msg .replyTo .send (response );
104
+ } catch (RemoteException e ) {
105
+ Log .e (TAG , "Unable to respond to getApplicationRestrictions." , e );
106
+ }
107
+ break ;
108
+ }
109
+ default :
110
+ throw new IllegalArgumentException ("Unknown 'what': " + msg .what );
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Called by a profile owner or device owner to grant permission to a package to manage
116
+ * application restrictions for the calling user via the {@link AppRestrictionsProxy}.
117
+ *
118
+ * This permission is persistent until it is later cleared by calling this method with a
119
+ * {@code null} value.
120
+ *
121
+ * The supplied application restriction managing package must be installed when calling this
122
+ * API, otherwise an {@link IllegalArgumentException} will be thrown.
123
+ */
124
+ public void setApplicationRestrictionsManagingPackage (String packageName ) {
125
+ if (packageName == null ) {
126
+ PreferenceManager .getDefaultSharedPreferences (mContext ).edit ()
127
+ .putStringSet (APPLICATION_RESTRICTIONS_MANAGING_PACKAGE_SIGNATURES_KEY , null );
128
+ PreferenceManager .getDefaultSharedPreferences (mContext ).edit ()
129
+ .putString (APPLICATION_RESTRICTIONS_MANAGING_PACKAGE_KEY , null );
130
+ return ;
131
+ }
132
+ Signature [] signatures ;
133
+ try {
134
+ PackageManager packageManager = mContext .getPackageManager ();
135
+ PackageInfo packageInfo =
136
+ packageManager .getPackageInfo (packageName , PackageManager .GET_SIGNATURES );
137
+ if (packageInfo == null ) {
138
+ throw new IllegalArgumentException ("Package info could not be retrieved for " +
139
+ "package " + packageName + "." );
140
+ }
141
+ signatures = packageInfo .signatures ;
142
+ if (signatures == null ) {
143
+ throw new IllegalArgumentException ("Package info did not contain signatures " +
144
+ "for package " + packageName + "." );
145
+ }
146
+ } catch (NameNotFoundException e ) {
147
+ throw new IllegalArgumentException ("Cannot set " + packageName + " as application " +
148
+ "restriction managing package as it is not installed." , e );
149
+ }
150
+ Set <String > signatureSet = new HashSet <>();
151
+ for (Signature signature : signatures ) {
152
+ signatureSet .add (signature .toCharsString ());
153
+ }
154
+
155
+ PreferenceManager .getDefaultSharedPreferences (mContext ).edit ()
156
+ .putStringSet (APPLICATION_RESTRICTIONS_MANAGING_PACKAGE_SIGNATURES_KEY ,
157
+ signatureSet );
158
+ PreferenceManager .getDefaultSharedPreferences (mContext ).edit ()
159
+ .putString (APPLICATION_RESTRICTIONS_MANAGING_PACKAGE_KEY , packageName );
160
+ }
161
+
162
+ /**
163
+ * Called by a profile owner or device owner to retrieve the application restrictions managing
164
+ * package for the current user, or {@code null} if none is set.
165
+ */
166
+ public String getApplicationRestrictionsManagingPackage (){
167
+ return PreferenceManager .getDefaultSharedPreferences (mContext )
168
+ .getString (APPLICATION_RESTRICTIONS_MANAGING_PACKAGE_KEY , null );
169
+ }
170
+
171
+ private void setApplicationRestrictions (String packageName , Bundle appRestrictions ){
172
+ if (packageName == null ) {
173
+ throw new IllegalArgumentException ("packageName cannot be null." );
174
+ }
175
+ if (appRestrictions == null ) {
176
+ throw new IllegalArgumentException ("applicationRestrictions bundle " +
177
+ "cannot be null." );
178
+ }
179
+ Log .d (TAG , "Setting application restrictions for package " + packageName );
180
+ DevicePolicyManager devicePolicyManager = (DevicePolicyManager )
181
+ mContext .getSystemService (Context .DEVICE_POLICY_SERVICE );
182
+ devicePolicyManager .setApplicationRestrictions (mAdmin , packageName ,
183
+ appRestrictions );
184
+ }
185
+
186
+ private Bundle getApplicationRestrictions (String packageName ){
187
+ if (packageName == null ) {
188
+ throw new IllegalArgumentException ("packageName cannot be null." );
189
+ }
190
+ DevicePolicyManager devicePolicyManager = (DevicePolicyManager )
191
+ mContext .getSystemService (Context .DEVICE_POLICY_SERVICE );
192
+ return devicePolicyManager .getApplicationRestrictions (mAdmin , packageName );
193
+ }
194
+
195
+ /**
196
+ * Checks that the message sent through the bound service was sent by the same package as
197
+ * declared in {@link #setApplicationRestrictionsManagingPackage(String)}, and
198
+ * that its signature has not changed since it was set.
199
+ *
200
+ * @param callerUid the UID of the caller
201
+ *
202
+ * @throws SecurityException if the DPC hasn't given permission to the caller to manage
203
+ * application restrictions, or if the calling package's signature has changed since it was
204
+ * set.
205
+ */
206
+ private void ensureCallerSignature (int callerUid ) {
207
+ String appRestrictionsManagingPackage = getApplicationRestrictionsManagingPackage ();
208
+ if (appRestrictionsManagingPackage == null ) {
209
+ throw new SecurityException ("Caller is not app restrictions managing package" );
210
+ }
211
+ PackageManager packageManager = mContext .getPackageManager ();
212
+ String callingPackageName = packageManager .getNameForUid (callerUid );
213
+ if (!appRestrictionsManagingPackage .equals (callingPackageName )) {
214
+ throw new SecurityException ("Caller is not app restrictions managing package" );
215
+ }
216
+
217
+ Set <String > storedSignatures = PreferenceManager .getDefaultSharedPreferences (mContext )
218
+ .getStringSet (APPLICATION_RESTRICTIONS_MANAGING_PACKAGE_SIGNATURES_KEY , null );
219
+ if (storedSignatures == null ) {
220
+ throw new IllegalStateException (
221
+ "App restrictions managing package signatures have not been stored." );
222
+ }
223
+ Signature [] callingPackageSignatures ;
224
+ try {
225
+ PackageInfo packageInfo = packageManager
226
+ .getPackageInfo (callingPackageName , PackageManager .GET_SIGNATURES );
227
+ if (packageInfo == null ) {
228
+ throw new IllegalArgumentException ("Package info could not be retrieved for " +
229
+ "package " + callingPackageName + "." );
230
+ }
231
+ callingPackageSignatures = packageInfo .signatures ;
232
+ if (callingPackageSignatures == null ) {
233
+ throw new IllegalArgumentException ("Package info did not contain signatures " +
234
+ "for package " + callingPackageName + "." );
235
+ }
236
+ } catch (NameNotFoundException e ) {
237
+ throw new SecurityException (e );
238
+ }
239
+ List <Signature > expectedSignatures = new ArrayList <>(storedSignatures .size ());
240
+ for (String signatureString : storedSignatures ) {
241
+ expectedSignatures .add (new Signature (signatureString ));
242
+ }
243
+ for (Signature callingSignature : callingPackageSignatures ) {
244
+ for (Signature expectedSignature : expectedSignatures ) {
245
+ if (expectedSignature .equals (callingSignature )) {
246
+ return ;
247
+ }
248
+ }
249
+ }
250
+ throw new SecurityException ("Calling package signature doesn't match" );
251
+ }
252
+ }
0 commit comments