content: package com.termux.shared.net.socket.local;
  
  import android.content.Context;
  
  import androidx.annotation.Keep;
  import androidx.annotation.NonNull;
  
  import com.termux.shared.android.ProcessUtils;
  import com.termux.shared.android.UserUtils;
  import com.termux.shared.logger.Logger;
  import com.termux.shared.markdown.MarkdownUtils;
  
  /** The {@link PeerCred} of the {@link LocalClientSocket} containing info of client/peer. */
  @Keep
  public class PeerCred {
  
      public static final String LOG_TAG = "PeerCred";
  
      /** Process Id. */
      public int pid;
      /** Process Name. */
      public String pname;
  
      /** User Id. */
      public int uid;
      /** User name. */
      public String uname;
  
      /** Group Id. */
      public int gid;
      /** Group name. */
      public String gname;
  
      /** Command line that started the process. */
      public String cmdline;
  
      PeerCred() {
          // Initialize to -1 instead of 0 in case a failed getPeerCred()/getsockopt() call somehow doesn't report failure and returns the uid of root
          pid = -1; uid = -1; gid = -1;
      }
  
      /** Set data that was not set by JNI. */
      public void fillPeerCred(@NonNull Context context) {
          fillUnameAndGname(context);
          fillPname(context);
      }
  
      /** Set {@link #uname} and {@link #gname} if not set. */
      public void fillUnameAndGname(@NonNull Context context) {
         uname = UserUtils.getNameForUid(context, uid);
  
         if (gid != uid)
             gname = UserUtils.getNameForUid(context, gid);
         else
             gname = uname;
      }
  
      /** Set {@link #pname} if not set. */
      public void fillPname(@NonNull Context context) {
          // If jni did not set process name since it wouldn't be able to access /proc/<pid> of other
          // users/apps, then try to see if any app has that pid, but this wouldn't check child
          // processes of the app.
          if (pid > 0 && pname == null)
              pname = ProcessUtils.getAppProcessNameForPid(context, pid);
      }
  
      /**
       * Get a log {@link String} for {@link PeerCred}.
       *
       * @param peerCred The {@link PeerCred} to get info of.
       * @return Returns the log {@link String}.
       */
      @NonNull
      public static String getPeerCredLogString(final PeerCred peerCred) {
          if (peerCred == null) return "null";
          return peerCred.getLogString();
      }
  
      /** Get a log {@link String} for the {@link PeerCred}. */
      @NonNull
      public String getLogString() {
          StringBuilder logString = new StringBuilder();
  
          logString.append("Peer Cred:");
          logString.append("\n").append(Logger.getSingleLineLogStringEntry("Process", getProcessString(), "-"));
          logString.append("\n").append(Logger.getSingleLineLogStringEntry("User", getUserString(), "-"));
          logString.append("\n").append(Logger.getSingleLineLogStringEntry("Group", getGroupString(), "-"));
  
          if (cmdline != null)
              logString.append("\n").append(Logger.getMultiLineLogStringEntry("Cmdline", cmdline, "-"));
  
          return logString.toString();
      }
  
      /**
       * Get a markdown {@link String} for {@link PeerCred}.
       *
       * @param peerCred The {@link PeerCred} to get info of.
       * @return Returns the markdown {@link String}.
       */
      public static String getPeerCredMarkdownString(final PeerCred peerCred) {
          if (peerCred == null) return "null";
          return peerCred.getMarkdownString();
      }
  
      /** Get a markdown {@link String} for the {@link PeerCred}. */
      @NonNull
      public String getMarkdownString() {
          StringBuilder markdownString = new StringBuilder();
  
          markdownString.append("## ").append("Peer Cred");
          markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Process", getProcessString(), "-"));
          markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("User", getUserString(), "-"));
          markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Group", getGroupString(), "-"));
  
          if (cmdline != null)
              markdownString.append("\n").append(MarkdownUtils.getMultiLineMarkdownStringEntry("Cmdline", cmdline, "-"));
  
          return markdownString.toString();
      }
  
      @NonNull
      public String getMinimalString() {
          return "process=" + getProcessString() + ", user=" + getUserString() + ", group=" + getGroupString();
      }
  
      @NonNull
      public String getProcessString() {
          return pname != null && !pname.isEmpty() ? pid + " (" + pname + ")" : String.valueOf(pid);
      }
  
      @NonNull
      public String getUserString() {
          return uname != null ? uid + " (" + uname + ")" : String.valueOf(uid);
      }
  
      @NonNull
      public String getGroupString() {
          return gname != null ? gid + " (" + gname + ")" : String.valueOf(gid);
      }
  
  }
  