@@ -75,59 +75,26 @@ def __init__(
75
75
}
76
76
self ._callbacks = {STATE_TYPE_HDR : None , STATE_TYPE_POWER : None }
77
77
78
- # Check for existence of ADB on the path
79
- try :
80
- self ._adb_path = subprocess .check_output (
81
- ("/usr/bin/which" , "adb" ), stderr = subprocess .DEVNULL
82
- ).strip ()
83
- except subprocess .CalledProcessError :
84
- print ("Error: adb util not found on path!" , file = sys .stderr )
85
- sys .exit (1 )
78
+ self ._ps = None
79
+ self ._pl_thread = None
86
80
87
- # Connect ADB to the SHIELD TV
88
- try :
89
- subprocess .check_output (
90
- (self ._adb_path , "connect" , f"{ hostname } :{ port } " ),
91
- stderr = subprocess .DEVNULL ,
92
- )
93
- except subprocess .CalledProcessError :
94
- print (
95
- "Unable to connect to adb port on SHIELD TV device "
96
- f"at { hostname } :{ port } ." ,
97
- file = sys .stderr ,
98
- )
99
- sys .exit (2 )
100
- finally :
101
- self ._connected = True
102
-
103
- # Flush the adb logs
104
- try :
105
- subprocess .check_output (
106
- (self ._adb_path , "logcat" , "-c" ),
107
- stderr = subprocess .DEVNULL ,
108
- )
109
- except subprocess .CalledProcessError :
110
- print ("Unable to flush adb logs" , file = sys .stderr )
111
- sys .exit (3 )
81
+ self ._queue = Queue ()
112
82
113
83
# Prepare common log parsing regex
114
- self .regex_log_parse = re .compile (
84
+ self ._regex_log_parse = re .compile (
115
85
r"^(?P<month>\d{2})-(?P<date>\d{2})\s+"
116
86
r"(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})\.(?P<millisecond>\d{3})\s+"
117
87
r"\d+\s+\d+\s+\w\s+(?P<process>\S+)\s*:\s+(?P<message>.+)$"
118
88
)
89
+ self ._regex_logcat_fails = [
90
+ re .compile ("logcat: Unexpected EOF!" )
91
+ ]
119
92
120
- # Start processing logs
121
- self ._ps = subprocess .Popen ((self ._adb_path , "logcat" ), stdout = subprocess .PIPE )
122
-
123
- self ._queue = Queue ()
124
- t = Thread (target = self ._process_log , args = (self ._ps .stdout , self ._queue ))
125
- t .daemon = True
126
- t .start ()
93
+ self ._adb_start ()
127
94
128
- def _process_log (self , output , queue : Queue ):
95
+ def _process_log (self , output , err , queue : Queue ):
129
96
for line in iter (output .readline , b"" ):
130
- matched_line = self .regex_log_parse .match (line .decode ("utf-8" ))
97
+ matched_line = self ._regex_log_parse .match (line .decode ("utf-8" ))
131
98
132
99
if matched_line :
133
100
process = matched_line .group ("process" )
@@ -156,8 +123,68 @@ def _process_log(self, output, queue: Queue):
156
123
}
157
124
)
158
125
126
+ for line in iter (err .readline , b"" ):
127
+ for fail in self ._regex_logcat_fails :
128
+ matched_line = fail .match (line .decode ("utf-8" ))
129
+
130
+ if matched_line :
131
+ # Terminate now, cleanup later
132
+ self ._ps .terminate ()
133
+
159
134
output .close ()
160
135
136
+ def _adb_start (self ):
137
+ # Check for existence of ADB on the path
138
+ try :
139
+ self ._adb_path = subprocess .check_output (
140
+ ("/usr/bin/which" , "adb" ), stderr = subprocess .DEVNULL
141
+ ).strip ()
142
+ except subprocess .CalledProcessError :
143
+ print ("Error: adb util not found on path!" , file = sys .stderr )
144
+ sys .exit (1 )
145
+
146
+ # Connect ADB to the SHIELD TV
147
+ while not self ._connected :
148
+ try :
149
+ subprocess .check_output (
150
+ (self ._adb_path , "connect" , f"{ self ._hostname } :{ self ._port } " ),
151
+ stderr = subprocess .DEVNULL ,
152
+ )
153
+ except subprocess .CalledProcessError :
154
+ print (
155
+ "Unable to connect to adb port on SHIELD TV device "
156
+ f"at { self ._hostname } :{ self ._port } ." ,
157
+ file = sys .stderr ,
158
+ )
159
+ time .sleep (5 )
160
+ finally :
161
+ self ._connected = True
162
+
163
+ # Flush the adb logs
164
+ try :
165
+ subprocess .check_output (
166
+ (self ._adb_path , "logcat" , "-c" ),
167
+ stderr = subprocess .DEVNULL ,
168
+ )
169
+ except subprocess .CalledProcessError :
170
+ print ("Unable to flush adb logs" , file = sys .stderr )
171
+ sys .exit (3 )
172
+
173
+ # Start processing logs
174
+ self ._ps = subprocess .Popen (
175
+ (self ._adb_path , "logcat" ), stdout = subprocess .PIPE , stderr = subprocess .PIPE
176
+ )
177
+
178
+ self ._pl_thread = Thread (target = self ._process_log , args = (self ._ps .stdout , self ._ps .stderr , self ._queue ))
179
+ self ._pl_thread .daemon = True
180
+ self ._pl_thread .start ()
181
+
182
+ def _check_adb_state (self ):
183
+ if self ._ps .poll () is not None :
184
+ self ._connected = False
185
+ print ("ADB process has died. Restarting..." )
186
+ self ._adb_start ()
187
+
161
188
def _update_states_from_queue (self ):
162
189
new_state = copy .deepcopy (self ._current_state )
163
190
@@ -185,4 +212,5 @@ def set_power_callback(self, callback):
185
212
self ._callbacks [STATE_TYPE_POWER ] = callback
186
213
187
214
def loop (self ):
215
+ self ._check_adb_state ()
188
216
self ._update_states_from_queue ()
0 commit comments