1 /*
2  * Copyright (C) 2017 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.appwithdata;
18 
19 import android.content.ContentProvider;
20 import android.content.ContentValues;
21 import android.database.Cursor;
22 import android.net.TrafficStats;
23 import android.net.Uri;
24 import android.os.Bundle;
25 import android.os.ParcelFileDescriptor;
26 import android.system.Os;
27 import android.util.Log;
28 
29 import java.io.IOException;
30 import java.net.ServerSocket;
31 import java.net.Socket;
32 
33 public class MyProvider extends ContentProvider {
34     private static final String TAG = "CTS";
35 
36     @Override
onCreate()37     public boolean onCreate() {
38         return true;
39     }
40 
41     @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)42     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
43             String sortOrder) {
44         throw new UnsupportedOperationException();
45     }
46 
47     @Override
getType(Uri uri)48     public String getType(Uri uri) {
49         throw new UnsupportedOperationException();
50     }
51 
52     @Override
insert(Uri uri, ContentValues values)53     public Uri insert(Uri uri, ContentValues values) {
54         throw new UnsupportedOperationException();
55     }
56 
57     @Override
delete(Uri uri, String selection, String[] selectionArgs)58     public int delete(Uri uri, String selection, String[] selectionArgs) {
59         throw new UnsupportedOperationException();
60     }
61 
62     @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)63     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
64         throw new UnsupportedOperationException();
65     }
66 
67     @Override
call(String method, String arg, Bundle extras)68     public Bundle call(String method, String arg, Bundle extras) {
69         Log.v(TAG, "call() " + method);
70         switch (method) {
71             case "start": {
72                 server = new EchoServer();
73                 server.start();
74                 extras = new Bundle();
75                 extras.putInt("port", server.server.getLocalPort());
76                 return extras;
77             }
78             case "stop": {
79                 server.halt();
80                 return null;
81             }
82             case "tag": {
83                 final int uid = Os.getuid();
84                 Log.v(TAG, "My UID is " + uid);
85                 TrafficStats.setThreadStatsUid(uid);
86                 if (TrafficStats.getThreadStatsUid() != uid) {
87                     throw new AssertionError("TrafficStats UID mismatch!");
88                 }
89                 try {
90                     final ParcelFileDescriptor pfd = extras.getParcelable("fd");
91                     TrafficStats.tagFileDescriptor(pfd.getFileDescriptor());
92                 } catch (IOException e) {
93                     throw new RuntimeException(e);
94                 } finally {
95                     TrafficStats.clearThreadStatsUid();
96                 }
97                 return null;
98             }
99             default: {
100                 throw new UnsupportedOperationException();
101             }
102         }
103     }
104 
105     private EchoServer server;
106 
107     private static class EchoServer extends Thread {
108         final ServerSocket server;
109         volatile boolean halted = false;
110 
EchoServer()111         public EchoServer() {
112             try {
113                 server = new ServerSocket(0);
114             } catch (IOException e) {
115                 throw new RuntimeException(e);
116             }
117         }
118 
halt()119         public void halt() {
120             halted = true;
121             try {
122                 server.close();
123             } catch (IOException e) {
124                 throw new RuntimeException(e);
125             }
126         }
127 
128         @Override
run()129         public void run() {
130             while (!halted) {
131                 try {
132                     final Socket socket = server.accept();
133                     socket.setTcpNoDelay(true);
134                     final int val = socket.getInputStream().read();
135                     socket.getOutputStream().write(val);
136                     socket.getOutputStream().flush();
137                     socket.close();
138                 } catch (IOException e) {
139                     Log.w(TAG, e);
140                 }
141             }
142         }
143     }
144 }
145