• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.textclassifier.testing;
17 
18 import java.io.BufferedReader;
19 import java.io.FileReader;
20 import java.io.IOException;
21 import java.util.HashMap;
22 import java.util.Map;
23 
24 /**
25  * Class for reading a process' signal masks from the /proc filesystem.  Looks for the
26  * BLOCKED, CAUGHT, IGNORED and PENDING masks from /proc/self/status, each of which is a
27  * 64 bit bitmask with one bit per signal.
28  *
29  * Maintains a map from SignalMaskInfo.Type to the bitmask.  The {@code isValid} method
30  * will only return true if all 4 masks were successfully parsed. Provides lookup
31  * methods per signal, e.g. {@code isPending(signum)} which will throw
32  * {@code IllegalStateException} if the current data is not valid.
33  */
34 public class SignalMaskInfo {
35     private enum Type {
36         BLOCKED("SigBlk"),
37         CAUGHT("SigCgt"),
38         IGNORED("SigIgn"),
39         PENDING("SigPnd");
40         // The tag for this mask in /proc/self/status
41         private final String tag;
42 
Type(String tag)43         Type(String tag) {
44             this.tag = tag + ":\t";
45         }
46 
getTag()47         public String getTag() {
48             return tag;
49         }
50 
parseProcinfo(String path)51         public static Map<Type, Long> parseProcinfo(String path) {
52             Map<Type, Long> map = new HashMap<>();
53             try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
54                 String line;
55                 while ((line = reader.readLine()) != null) {
56                     for (Type mask : values()) {
57                         long value = mask.tryToParse(line);
58                         if (value >= 0) {
59                             map.put(mask, value);
60                         }
61                     }
62                 }
63             } catch (NumberFormatException | IOException e) {
64                 // Ignored - the map will end up being invalid instead.
65             }
66             return map;
67         }
68 
tryToParse(String line)69         private long tryToParse(String line) {
70             if (line.startsWith(tag)) {
71                 return Long.valueOf(line.substring(tag.length()), 16);
72             } else {
73                 return -1;
74             }
75         }
76     }
77 
78     private static final String PROCFS_PATH = "/proc/self/status";
79     private Map<Type, Long> maskMap = null;
80 
SignalMaskInfo()81     SignalMaskInfo() {
82         refresh();
83     }
84 
refresh()85     public void refresh() {
86         maskMap = Type.parseProcinfo(PROCFS_PATH);
87     }
88 
isValid()89     public boolean isValid() {
90         return (maskMap != null && maskMap.size() == Type.values().length);
91     }
92 
isCaught(int signal)93     public boolean isCaught(int signal) {
94         return isSignalInMask(signal, Type.CAUGHT);
95     }
96 
isBlocked(int signal)97     public boolean isBlocked(int signal) {
98         return isSignalInMask(signal, Type.BLOCKED);
99     }
100 
isPending(int signal)101     public boolean isPending(int signal) {
102         return isSignalInMask(signal, Type.PENDING);
103     }
104 
isIgnored(int signal)105     public boolean isIgnored(int signal) {
106         return isSignalInMask(signal, Type.IGNORED);
107     }
108 
checkValid()109     private void checkValid() {
110         if (!isValid()) {
111             throw new IllegalStateException();
112         }
113     }
114 
isSignalInMask(int signal, Type mask)115     private boolean isSignalInMask(int signal, Type mask) {
116         long bit = 1L << (signal - 1);
117         return (getSignalMask(mask) & bit) != 0;
118     }
119 
getSignalMask(Type mask)120     private long getSignalMask(Type mask) {
121         checkValid();
122         Long value = maskMap.get(mask);
123         if (value == null) {
124             throw new IllegalStateException();
125         }
126         return value;
127     }
128 }
129