1 /*
2  * Copyright (C) 2020 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.cts.useprocess;
18 
19 import android.app.Service;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.os.Binder;
23 import android.os.IBinder;
24 import android.os.Parcel;
25 import android.os.Process;
26 import android.os.RemoteException;
27 import android.os.StrictMode;
28 import android.util.Log;
29 
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import java.io.PrintWriter;
34 import java.io.StringWriter;
35 import java.net.ServerSocket;
36 import java.net.Socket;
37 import java.net.SocketException;
38 
39 public class BaseNetworkService extends Service {
40     private static final String LOG_TAG = "ServiceWithInternet";
41 
42     public static final int TRANSACT_TEST = IBinder.FIRST_CALL_TRANSACTION;
43 
44     final boolean mNetworkAllowed;
45     final String mExpectedProcessName;
46 
readResult(Parcel in)47     public static final String readResult(Parcel in) {
48         if (in.readInt() != 0) {
49             return in.readString();
50         } else {
51             return null;
52         }
53     }
54 
readResultCallstack(Parcel in)55     public static final String readResultCallstack(Parcel in) {
56         return in.readString();
57     }
58 
writeResult(Parcel out, String errorMsg, Throwable where)59     static final void writeResult(Parcel out, String errorMsg, Throwable where) {
60         if (errorMsg != null) {
61             out.writeInt(1);
62             out.writeString(errorMsg);
63             if (where == null) {
64                 where = new Exception();
65                 where.fillInStackTrace();
66             }
67             StringWriter sw = new StringWriter();
68             PrintWriter pw = new PrintWriter(sw, false);
69             where.printStackTrace(pw);
70             pw.flush();
71             out.writeString(sw.toString());
72         } else {
73             out.writeInt(0);
74         }
75     }
76 
77     private final IBinder mBinder = new Binder() {
78         @Override
79         protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
80                 throws RemoteException {
81             if (code == TRANSACT_TEST) {
82                 try {
83                     StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
84                             .permitNetwork().build());
85                     doTest(reply);
86                 } catch (Throwable e) {
87                     writeResult(reply, "Unexpected exception: " + e, e);
88                 }
89                 return true;
90             } else {
91                 return super.onTransact(code, data, reply, flags);
92             }
93         }
94 
95         private void doTest(Parcel reply) {
96             if (!mExpectedProcessName.equals(getApplication().getProcessName())) {
97                 writeResult(reply,
98                         "Not running in correct process, expected " + mExpectedProcessName
99                         + " but got " + getApplication().getProcessName(),null);
100                 return;
101             }
102 
103             try {
104                 Socket socket = new Socket("example.com", 80);
105                 socket.close();
106                 if (!mNetworkAllowed) {
107                     writeResult(reply,
108                             "Create inet socket did not throw SecurityException as expected",
109                             null);
110                     return;
111                 }
112             } catch (SecurityException e) {
113                 if (mNetworkAllowed) {
114                     writeResult(reply,
115                             "Create inet socket should be allowed but: " + e, e);
116                     return;
117                 }
118             } catch (IOException e) {
119                 if (!mNetworkAllowed) {
120                     writeResult(reply,
121                             "Create inet socket did not throw SecurityException as expected", e);
122                     return;
123                 }
124             }
125 
126             int hasPerm = checkPermission(android.Manifest.permission.INTERNET,
127                     Process.myPid(), Process.myUid());
128             if (mNetworkAllowed) {
129                 if (hasPerm != PackageManager.PERMISSION_GRANTED) {
130                     writeResult(reply, "Should have INTERNET permission, but got: " + hasPerm,
131                             null);
132                     return;
133                 }
134             } else {
135                 if (hasPerm != PackageManager.PERMISSION_DENIED) {
136                     writeResult(reply, "Shouldn't have INTERNET permission, but got: " + hasPerm,
137                             null);
138                     return;
139                 }
140             }
141 
142             // A local socket binding is not allowed if you don't have network access, and
143             // also not allowed for instant aps.
144             final boolean allowLocalSocket = mNetworkAllowed
145                     && !getPackageManager().isInstantApp();
146 
147             try {
148                 // Transfer 128K of data across an explicitly localhost socket.
149                 final int byteCount = 1024;
150                 final int packetCount = 128;
151                 final ServerSocket server;
152                 try {
153                     server = new ServerSocket(0);
154                     if (!allowLocalSocket) {
155                         server.close();
156                         writeResult(reply,
157                                 "Create local socket did not throw SecurityException as expected",
158                                 null);
159                         return;
160                     }
161                 } catch (SocketException e) {
162                     if (allowLocalSocket) {
163                         writeResult(reply,
164                                 "Create local socket should be allowed but: " + e, null);
165                     }
166                     return;
167                 }
168                 new Thread("TrafficStatsTest.testTrafficStatsForLocalhost") {
169                     @Override
170                     public void run() {
171                         try {
172                             Socket socket = new Socket("localhost", server.getLocalPort());
173                             OutputStream out = socket.getOutputStream();
174                             byte[] buf = new byte[byteCount];
175                             for (int i = 0; i < packetCount; i++) {
176                                 out.write(buf);
177                                 out.flush();
178                             }
179                             out.close();
180                             socket.close();
181                         } catch (IOException e) {
182                             writeResult(reply, "Badness during writes to socket: " + e, e);
183                             return;
184                         }
185                     }
186                 }.start();
187 
188                 int read = 0;
189                 try {
190                     Socket socket = server.accept();
191                     InputStream in = socket.getInputStream();
192                     byte[] buf = new byte[byteCount];
193                     while (read < byteCount * packetCount) {
194                         int n = in.read(buf);
195                         if (n <= 0) {
196                             writeResult(reply, "Unexpected EOF @ " + read,null);
197                             return;
198                         }
199                         read += n;
200                     }
201                 } finally {
202                     server.close();
203                 }
204                 if (read != (byteCount * packetCount)) {
205                     writeResult(reply, "Not all data read back: expected "
206                             + (byteCount * packetCount) + ", received" + read, null);
207                     return;
208 
209                 }
210             } catch (IOException e) {
211                 writeResult(reply, e.toString(), e);
212                 return;
213             }
214 
215             writeResult(reply, null, null);
216         }
217     };
218 
BaseNetworkService(boolean networkAllowed, String expectedProcessName)219     public BaseNetworkService(boolean networkAllowed, String expectedProcessName) {
220         mNetworkAllowed = networkAllowed;
221         mExpectedProcessName = expectedProcessName;
222     }
223 
224     @Override
onBind(Intent intent)225     public IBinder onBind(Intent intent) {
226         return mBinder;
227     }
228 }
229