If setup fails, hang forever

Without this init will repeatedly try to start this daemon,
causing logspam.

Also:
* wait until just before tokio conversion to set O_NONBLOCK
* ensure logging code reflects source example
* log at info and higher
* use contexts for better logging
* fall back to println to work around logging problems
* remove wrong copy-pasted comment in Android.bp

Bug: 249531229
Fixes: 249566340
Test: in permissive mode, rm /dev/hw_random before start
Change-Id: Ib70cbcb048f33dca789151622d98c6d56270fa37
Merged-In: Ib70cbcb048f33dca789151622d98c6d56270fa37
(cherry picked from commit 021cf557e6cdf1ff0779e87834532c0e0e893ef8)
(cherry picked from commit 4e6fe88753fddbb4da0ffd8574c389d1255baf65)
Merged-In: Ib70cbcb048f33dca789151622d98c6d56270fa37
diff --git a/prng_seeder/Android.bp b/prng_seeder/Android.bp
index ea4f00f..2be20a9 100644
--- a/prng_seeder/Android.bp
+++ b/prng_seeder/Android.bp
@@ -14,9 +14,6 @@
 
 package {
     // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "external_boringssl_license"
-    // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["system_security_license"],
 }
diff --git a/prng_seeder/src/conditioner.rs b/prng_seeder/src/conditioner.rs
index 66b29a4..eca8af8 100644
--- a/prng_seeder/src/conditioner.rs
+++ b/prng_seeder/src/conditioner.rs
@@ -12,10 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use std::{fs::File, io::Read};
+use std::{fs::File, io::Read, os::unix::io::AsRawFd};
 
-use anyhow::{ensure, Result};
+use anyhow::{ensure, Context, Result};
 use log::debug;
+use nix::fcntl::{fcntl, FcntlArg::F_SETFL, OFlag};
 use tokio::io::AsyncReadExt;
 
 use crate::drbg;
@@ -23,6 +24,30 @@
 const SEED_FOR_CLIENT_LEN: usize = 496;
 const NUM_REQUESTS_PER_RESEED: u32 = 256;
 
+pub struct ConditionerBuilder {
+    hwrng: File,
+    rg: drbg::Drbg,
+}
+
+impl ConditionerBuilder {
+    pub fn new(mut hwrng: File) -> Result<ConditionerBuilder> {
+        let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
+        hwrng.read_exact(&mut et).context("hwrng.read_exact in new")?;
+        let rg = drbg::Drbg::new(&et)?;
+        fcntl(hwrng.as_raw_fd(), F_SETFL(OFlag::O_NONBLOCK))
+            .context("setting O_NONBLOCK on hwrng")?;
+        Ok(ConditionerBuilder { hwrng, rg })
+    }
+
+    pub fn build(self) -> Conditioner {
+        Conditioner {
+            hwrng: tokio::fs::File::from_std(self.hwrng),
+            rg: self.rg,
+            requests_since_reseed: 0,
+        }
+    }
+}
+
 pub struct Conditioner {
     hwrng: tokio::fs::File,
     rg: drbg::Drbg,
@@ -30,18 +55,11 @@
 }
 
 impl Conditioner {
-    pub fn new(mut hwrng: File) -> Result<Conditioner> {
-        let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
-        hwrng.read_exact(&mut et)?;
-        let rg = drbg::Drbg::new(&et)?;
-        Ok(Conditioner { hwrng: tokio::fs::File::from_std(hwrng), rg, requests_since_reseed: 0 })
-    }
-
     pub async fn reseed_if_necessary(&mut self) -> Result<()> {
         if self.requests_since_reseed >= NUM_REQUESTS_PER_RESEED {
             debug!("Reseeding DRBG");
             let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
-            self.hwrng.read_exact(&mut et).await?;
+            self.hwrng.read_exact(&mut et).await.context("hwrng.read_exact in reseed")?;
             self.rg.reseed(&et)?;
             self.requests_since_reseed = 0;
         }
diff --git a/prng_seeder/src/main.rs b/prng_seeder/src/main.rs
index 8062d9a..10f853d 100644
--- a/prng_seeder/src/main.rs
+++ b/prng_seeder/src/main.rs
@@ -23,21 +23,18 @@
 
 use std::{
     convert::Infallible,
-    fs::{remove_file, File},
+    fs::remove_file,
     io::ErrorKind,
-    os::unix::{net::UnixListener, prelude::AsRawFd},
+    os::unix::net::UnixListener,
     path::{Path, PathBuf},
 };
 
-use anyhow::Result;
-use log::{error, info};
-use nix::{
-    fcntl::{fcntl, FcntlArg::F_SETFL, OFlag},
-    sys::signal,
-};
+use anyhow::{ensure, Context, Result};
+use log::{error, info, Level};
+use nix::sys::signal;
 use tokio::{io::AsyncWriteExt, net::UnixListener as TokioUnixListener};
 
-use crate::conditioner::Conditioner;
+use crate::conditioner::ConditionerBuilder;
 
 //#[derive(Debug, clap::Parser)]
 struct Cli {
@@ -47,24 +44,50 @@
     socket: Option<PathBuf>,
 }
 
-fn configure_logging() {
-    logger::init(Default::default());
+fn configure_logging() -> Result<()> {
+    ensure!(
+        logger::init(
+            logger::Config::default().with_tag_on_device("prng_seeder").with_min_level(Level::Info)
+        ),
+        "log configuration failed"
+    );
+    Ok(())
 }
 
 fn get_socket(path: &Path) -> Result<UnixListener> {
     if let Err(e) = remove_file(path) {
         if e.kind() != ErrorKind::NotFound {
-            return Err(e.into());
+            return Err(e).context(format!("Removing old socket: {}", path.display()));
         }
     } else {
-        info!("Deleted old {}", path.to_string_lossy());
+        info!("Deleted old {}", path.display());
     }
-    Ok(UnixListener::bind(path)?)
+    UnixListener::bind(path)
+        .with_context(|| format!("In get_socket: binding socket to {}", path.display()))
 }
 
-async fn listen_loop(hwrng: File, listener: UnixListener) -> Result<Infallible> {
-    let mut conditioner = Conditioner::new(hwrng)?;
-    let listener = TokioUnixListener::from_std(listener)?;
+fn setup() -> Result<(ConditionerBuilder, UnixListener)> {
+    configure_logging()?;
+    let cli = Cli { source: PathBuf::from("/dev/hw_random"), socket: None };
+    unsafe { signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigIgn) }
+        .context("In setup, setting SIGPIPE to SIG_IGN")?;
+
+    let listener = match cli.socket {
+        Some(path) => get_socket(path.as_path())?,
+        None => cutils_socket::android_get_control_socket("prng_seeder")
+            .context("In setup, calling android_get_control_socket")?,
+    };
+    let hwrng = std::fs::File::open(&cli.source)
+        .with_context(|| format!("Unable to open hwrng {}", cli.source.display()))?;
+    let cb = ConditionerBuilder::new(hwrng)?;
+    Ok((cb, listener))
+}
+
+async fn listen_loop(cb: ConditionerBuilder, listener: UnixListener) -> Result<Infallible> {
+    let mut conditioner = cb.build();
+    listener.set_nonblocking(true).context("In listen_loop, on set_nonblocking")?;
+    let listener = TokioUnixListener::from_std(listener).context("In listen_loop, on from_std")?;
+    info!("Starting listen loop");
     loop {
         match listener.accept().await {
             Ok((mut stream, _)) => {
@@ -77,35 +100,37 @@
                 conditioner.reseed_if_necessary().await?;
             }
             Err(e) if e.kind() == ErrorKind::Interrupted => {}
-            Err(e) => return Err(e.into()),
+            Err(e) => return Err(e).context("accept on socket failed"),
         }
     }
 }
 
-fn run(cli: Cli) -> Result<Infallible> {
-    let hwrng = std::fs::File::open(&cli.source)?;
-    fcntl(hwrng.as_raw_fd(), F_SETFL(OFlag::O_NONBLOCK))?;
-    let listener = match cli.socket {
-        Some(path) => get_socket(path.as_path())?,
-        None => cutils_socket::android_get_control_socket("prng_seeder")?,
+fn run() -> Result<Infallible> {
+    let (cb, listener) = match setup() {
+        Ok(t) => t,
+        Err(e) => {
+            // If setup fails, just hang forever. That way init doesn't respawn us.
+            error!("Hanging forever because setup failed: {:?}", e);
+            // Logs are sometimes mysteriously not being logged, so print too
+            println!("prng_seeder: Hanging forever because setup failed: {:?}", e);
+            loop {
+                std::thread::park();
+                error!("std::thread::park() finished unexpectedly, re-parking thread");
+            }
+        }
     };
-    listener.set_nonblocking(true)?;
-
-    unsafe { signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigIgn) }?;
 
     tokio::runtime::Builder::new_current_thread()
         .enable_all()
-        .build()?
-        .block_on(async { listen_loop(hwrng, listener).await })
+        .build()
+        .context("In run, building reactor")?
+        .block_on(async { listen_loop(cb, listener).await })
 }
 
 fn main() {
-    let cli = Cli { source: PathBuf::from("/dev/hw_random"), socket: None };
-    configure_logging();
-    if let Err(e) = run(cli) {
-        error!("Launch failed: {}", e);
-    } else {
-        error!("Loop terminated without an error")
-    }
+    let e = run();
+    error!("Launch terminated: {:?}", e);
+    // Logs are sometimes mysteriously not being logged, so print too
+    println!("prng_seeder: launch terminated: {:?}", e);
     std::process::exit(-1);
 }