1 /* 2 * Copyright 2019 The gRPC Authors 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 io.grpc.strictmodehelloworldexample; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.content.Context; 22 import android.net.TrafficStats; 23 import android.os.AsyncTask; 24 import android.os.Bundle; 25 import android.os.StrictMode; 26 import android.os.StrictMode.OnVmViolationListener; 27 import android.os.StrictMode.VmPolicy; 28 import android.os.strictmode.Violation; 29 import android.support.v7.app.AppCompatActivity; 30 import android.text.TextUtils; 31 import android.text.method.ScrollingMovementMethod; 32 import android.view.View; 33 import android.view.inputmethod.InputMethodManager; 34 import android.widget.Button; 35 import android.widget.EditText; 36 import android.widget.TextView; 37 import com.google.common.util.concurrent.MoreExecutors; 38 import com.google.common.util.concurrent.ThreadFactoryBuilder; 39 import io.grpc.ManagedChannel; 40 import io.grpc.examples.helloworld.GreeterGrpc; 41 import io.grpc.examples.helloworld.HelloReply; 42 import io.grpc.examples.helloworld.HelloRequest; 43 import io.grpc.okhttp.OkHttpChannelBuilder; 44 import java.io.PrintWriter; 45 import java.io.StringWriter; 46 import java.lang.ref.WeakReference; 47 import java.util.concurrent.SynchronousQueue; 48 import java.util.concurrent.ThreadPoolExecutor; 49 import java.util.concurrent.TimeUnit; 50 51 public class StrictModeHelloworldActivity extends AppCompatActivity { 52 private Button sendButton; 53 private EditText hostEdit; 54 private EditText portEdit; 55 private EditText messageEdit; 56 private TextView resultText; 57 58 @Override onCreate(Bundle savedInstanceState)59 protected void onCreate(Bundle savedInstanceState) { 60 super.onCreate(savedInstanceState); 61 VmPolicy policy = 62 new StrictMode.VmPolicy.Builder() 63 .detectCleartextNetwork() 64 .penaltyListener( 65 MoreExecutors.directExecutor(), 66 new OnVmViolationListener() { 67 @Override 68 public void onVmViolation(final Violation v) { 69 runOnUiThread( 70 new Runnable() { 71 @Override 72 public void run() { 73 new AlertDialog.Builder(StrictModeHelloworldActivity.this) 74 .setTitle("StrictMode VM Violation") 75 .setMessage(v.getLocalizedMessage()) 76 .show(); 77 } 78 }); 79 } 80 }) 81 .penaltyLog() 82 .build(); 83 StrictMode.setVmPolicy(policy); 84 setContentView(R.layout.activity_strictmodehelloworld); 85 sendButton = (Button) findViewById(R.id.send_button); 86 hostEdit = (EditText) findViewById(R.id.host_edit_text); 87 portEdit = (EditText) findViewById(R.id.port_edit_text); 88 messageEdit = (EditText) findViewById(R.id.message_edit_text); 89 resultText = (TextView) findViewById(R.id.grpc_response_text); 90 resultText.setMovementMethod(new ScrollingMovementMethod()); 91 } 92 sendMessage(View view)93 public void sendMessage(View view) { 94 ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) 95 .hideSoftInputFromWindow(hostEdit.getWindowToken(), 0); 96 sendButton.setEnabled(false); 97 resultText.setText(""); 98 new GrpcTask(this) 99 .execute( 100 hostEdit.getText().toString(), 101 messageEdit.getText().toString(), 102 portEdit.getText().toString()); 103 } 104 105 private static class GrpcTask extends AsyncTask<String, Void, String> { 106 private final WeakReference<Activity> activityReference; 107 private ManagedChannel channel; 108 GrpcTask(Activity activity)109 private GrpcTask(Activity activity) { 110 this.activityReference = new WeakReference<Activity>(activity); 111 } 112 113 @Override doInBackground(String... params)114 protected String doInBackground(String... params) { 115 String host = params[0]; 116 String message = params[1]; 117 String portStr = params[2]; 118 int port = TextUtils.isEmpty(portStr) ? 0 : Integer.valueOf(portStr); 119 try { 120 channel = 121 OkHttpChannelBuilder.forAddress(host, port) 122 .transportExecutor(new NetworkTaggingExecutor(0xFDD)) 123 .usePlaintext() 124 .build(); 125 GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel); 126 HelloRequest request = HelloRequest.newBuilder().setName(message).build(); 127 HelloReply reply = stub.sayHello(request); 128 return reply.getMessage(); 129 } catch (Exception e) { 130 StringWriter sw = new StringWriter(); 131 PrintWriter pw = new PrintWriter(sw); 132 e.printStackTrace(pw); 133 pw.flush(); 134 return String.format("Failed... : %n%s", sw); 135 } 136 } 137 138 @Override onPostExecute(String result)139 protected void onPostExecute(String result) { 140 try { 141 channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); 142 } catch (InterruptedException e) { 143 Thread.currentThread().interrupt(); 144 } 145 Activity activity = activityReference.get(); 146 if (activity == null) { 147 return; 148 } 149 TextView resultText = (TextView) activity.findViewById(R.id.grpc_response_text); 150 Button sendButton = (Button) activity.findViewById(R.id.send_button); 151 resultText.setText(result); 152 sendButton.setEnabled(true); 153 } 154 } 155 156 private static class NetworkTaggingExecutor extends ThreadPoolExecutor { 157 158 private int trafficStatsTag; 159 NetworkTaggingExecutor(int tag)160 NetworkTaggingExecutor(int tag) { 161 super( 162 0, 163 Integer.MAX_VALUE, 164 60L, 165 TimeUnit.SECONDS, 166 new SynchronousQueue<Runnable>(), 167 new ThreadFactoryBuilder().setDaemon(true).setNameFormat("grpc-android-%d").build()); 168 trafficStatsTag = tag; 169 } 170 171 @Override beforeExecute(Thread t, Runnable r)172 protected void beforeExecute(Thread t, Runnable r) { 173 TrafficStats.setThreadStatsTag(trafficStatsTag); 174 super.beforeExecute(t, r); 175 } 176 177 @Override afterExecute(Runnable r, Throwable t)178 protected void afterExecute(Runnable r, Throwable t) { 179 TrafficStats.clearThreadStatsTag(); 180 super.afterExecute(r, t); 181 } 182 } 183 } 184