1 /*
2  * Copyright (C) 2014 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 android.app;
18 
19 import android.os.Parcel;
20 import android.os.ParcelFileDescriptor;
21 import android.os.Parcelable;
22 import android.util.Slog;
23 import android.util.proto.ProtoOutputStream;
24 
25 import java.io.IOException;
26 import java.util.Objects;
27 
28 /**
29  * System private API for passing profiler settings.
30  *
31  * {@hide}
32  */
33 public class ProfilerInfo implements Parcelable {
34 
35     private static final String TAG = "ProfilerInfo";
36 
37     /* Name of profile output file. */
38     public final String profileFile;
39 
40     /* File descriptor for profile output file, can be null. */
41     public ParcelFileDescriptor profileFd;
42 
43     /* Indicates sample profiling when nonzero, interval in microseconds. */
44     public final int samplingInterval;
45 
46     /* Automatically stop the profiler when the app goes idle. */
47     public final boolean autoStopProfiler;
48 
49     /*
50      * Indicates whether to stream the profiling info to the out file continuously.
51      */
52     public final boolean streamingOutput;
53 
54     /**
55      * Denotes an agent (and its parameters) to attach for profiling.
56      */
57     public final String agent;
58 
59     /**
60      * Whether the {@link agent} should be attached early (before bind-application) or during
61      * bind-application. Agents attached prior to binding cannot be loaded from the app's APK
62      * directly and must be given as an absolute path (or available in the default LD_LIBRARY_PATH).
63      * Agents attached during bind-application will miss early setup (e.g., resource initialization
64      * and classloader generation), but are searched in the app's library search path.
65      */
66     public final boolean attachAgentDuringBind;
67 
ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop, boolean streaming, String agent, boolean attachAgentDuringBind)68     public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop,
69             boolean streaming, String agent, boolean attachAgentDuringBind) {
70         profileFile = filename;
71         profileFd = fd;
72         samplingInterval = interval;
73         autoStopProfiler = autoStop;
74         streamingOutput = streaming;
75         this.agent = agent;
76         this.attachAgentDuringBind = attachAgentDuringBind;
77     }
78 
ProfilerInfo(ProfilerInfo in)79     public ProfilerInfo(ProfilerInfo in) {
80         profileFile = in.profileFile;
81         profileFd = in.profileFd;
82         samplingInterval = in.samplingInterval;
83         autoStopProfiler = in.autoStopProfiler;
84         streamingOutput = in.streamingOutput;
85         agent = in.agent;
86         attachAgentDuringBind = in.attachAgentDuringBind;
87     }
88 
89     /**
90      * Return a new ProfilerInfo instance, with fields populated from this object,
91      * and {@link agent} and {@link attachAgentDuringBind} as given.
92      */
setAgent(String agent, boolean attachAgentDuringBind)93     public ProfilerInfo setAgent(String agent, boolean attachAgentDuringBind) {
94         return new ProfilerInfo(this.profileFile, this.profileFd, this.samplingInterval,
95                 this.autoStopProfiler, this.streamingOutput, agent, attachAgentDuringBind);
96     }
97 
98     /**
99      * Close profileFd, if it is open. The field will be null after a call to this function.
100      */
closeFd()101     public void closeFd() {
102         if (profileFd != null) {
103             try {
104                 profileFd.close();
105             } catch (IOException e) {
106                 Slog.w(TAG, "Failure closing profile fd", e);
107             }
108             profileFd = null;
109         }
110     }
111 
112     @Override
describeContents()113     public int describeContents() {
114         if (profileFd != null) {
115             return profileFd.describeContents();
116         } else {
117             return 0;
118         }
119     }
120 
121     @Override
writeToParcel(Parcel out, int flags)122     public void writeToParcel(Parcel out, int flags) {
123         out.writeString(profileFile);
124         if (profileFd != null) {
125             out.writeInt(1);
126             profileFd.writeToParcel(out, flags);
127         } else {
128             out.writeInt(0);
129         }
130         out.writeInt(samplingInterval);
131         out.writeInt(autoStopProfiler ? 1 : 0);
132         out.writeInt(streamingOutput ? 1 : 0);
133         out.writeString(agent);
134         out.writeBoolean(attachAgentDuringBind);
135     }
136 
137     /** @hide */
dumpDebug(ProtoOutputStream proto, long fieldId)138     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
139         final long token = proto.start(fieldId);
140         proto.write(ProfilerInfoProto.PROFILE_FILE, profileFile);
141         if (profileFd != null) {
142             proto.write(ProfilerInfoProto.PROFILE_FD, profileFd.getFd());
143         }
144         proto.write(ProfilerInfoProto.SAMPLING_INTERVAL, samplingInterval);
145         proto.write(ProfilerInfoProto.AUTO_STOP_PROFILER, autoStopProfiler);
146         proto.write(ProfilerInfoProto.STREAMING_OUTPUT, streamingOutput);
147         proto.write(ProfilerInfoProto.AGENT, agent);
148         proto.end(token);
149     }
150 
151     public static final @android.annotation.NonNull Parcelable.Creator<ProfilerInfo> CREATOR =
152             new Parcelable.Creator<ProfilerInfo>() {
153                 @Override
154                 public ProfilerInfo createFromParcel(Parcel in) {
155                     return new ProfilerInfo(in);
156                 }
157 
158                 @Override
159                 public ProfilerInfo[] newArray(int size) {
160                     return new ProfilerInfo[size];
161                 }
162             };
163 
ProfilerInfo(Parcel in)164     private ProfilerInfo(Parcel in) {
165         profileFile = in.readString();
166         profileFd = in.readInt() != 0 ? ParcelFileDescriptor.CREATOR.createFromParcel(in) : null;
167         samplingInterval = in.readInt();
168         autoStopProfiler = in.readInt() != 0;
169         streamingOutput = in.readInt() != 0;
170         agent = in.readString();
171         attachAgentDuringBind = in.readBoolean();
172     }
173 
174     @Override
equals(Object o)175     public boolean equals(Object o) {
176         if (this == o) {
177             return true;
178         }
179         if (o == null || getClass() != o.getClass()) {
180             return false;
181         }
182         final ProfilerInfo other = (ProfilerInfo) o;
183         // TODO: Also check #profileFd for equality.
184         return Objects.equals(profileFile, other.profileFile)
185                 && autoStopProfiler == other.autoStopProfiler
186                 && samplingInterval == other.samplingInterval
187                 && streamingOutput == other.streamingOutput
188                 && Objects.equals(agent, other.agent);
189     }
190 
191     @Override
hashCode()192     public int hashCode() {
193         int result = 17;
194         result = 31 * result + Objects.hashCode(profileFile);
195         result = 31 * result + samplingInterval;
196         result = 31 * result + (autoStopProfiler ? 1 : 0);
197         result = 31 * result + (streamingOutput ? 1 : 0);
198         result = 31 * result + Objects.hashCode(agent);
199         return result;
200     }
201 }
202